From 7d2d9364bb792ca1488e548e5a9be325c1b09798 Mon Sep 17 00:00:00 2001 From: gengminy Date: Sat, 24 Sep 2022 18:19:25 +0900 Subject: [PATCH 01/72] =?UTF-8?q?:rocket:=20feat(user):=20=EC=9C=A0?= =?UTF-8?q?=EC=A0=80=20=EC=97=94=ED=8B=B0=ED=8B=B0=20=EA=B5=AC=ED=98=84=20?= =?UTF-8?q?#18?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .github/workflows/deploy-dev.yml | 2 +- .github/workflows/deploy-prod.yml | 2 +- .../domain/member/MemberController.java | 34 ++++++++ .../domain/member/MemberDetailRepository.java | 9 ++ .../domain/member/MemberRepository.java | 9 ++ .../domain/member/MemberService.java | 76 +++++++++++++++++ .../domain/member/entity/Member.java | 85 +++++++++++++++++++ .../domain/member/entity/MemberDetail.java | 82 ++++++++++++++++++ .../domain/point/PointController.java | 7 ++ .../domain/point/PointRepository.java | 4 + .../naechinso/domain/point/PointService.java | 7 ++ .../naechinso/domain/point/entity/Point.java | 41 +++++++++ .../domain/recommend/RecommendController.java | 7 ++ .../domain/recommend/RecommendRepository.java | 4 + .../domain/recommend/RecommendService.java | 7 ++ .../domain/recommend/entity/Recommend.java | 26 ++++++ .../global/config/entity/BaseEntity.java | 5 +- .../global/config/entity/BaseTimeEntity.java | 5 +- 18 files changed, 405 insertions(+), 7 deletions(-) create mode 100644 src/main/java/com/tikitaka/naechinso/domain/member/MemberController.java create mode 100644 src/main/java/com/tikitaka/naechinso/domain/member/MemberDetailRepository.java create mode 100644 src/main/java/com/tikitaka/naechinso/domain/member/MemberRepository.java create mode 100644 src/main/java/com/tikitaka/naechinso/domain/member/MemberService.java create mode 100644 src/main/java/com/tikitaka/naechinso/domain/member/entity/Member.java create mode 100644 src/main/java/com/tikitaka/naechinso/domain/member/entity/MemberDetail.java create mode 100644 src/main/java/com/tikitaka/naechinso/domain/point/PointController.java create mode 100644 src/main/java/com/tikitaka/naechinso/domain/point/PointRepository.java create mode 100644 src/main/java/com/tikitaka/naechinso/domain/point/PointService.java create mode 100644 src/main/java/com/tikitaka/naechinso/domain/point/entity/Point.java create mode 100644 src/main/java/com/tikitaka/naechinso/domain/recommend/RecommendController.java create mode 100644 src/main/java/com/tikitaka/naechinso/domain/recommend/RecommendRepository.java create mode 100644 src/main/java/com/tikitaka/naechinso/domain/recommend/RecommendService.java create mode 100644 src/main/java/com/tikitaka/naechinso/domain/recommend/entity/Recommend.java diff --git a/.github/workflows/deploy-dev.yml b/.github/workflows/deploy-dev.yml index 5a54175..3da86ce 100644 --- a/.github/workflows/deploy-dev.yml +++ b/.github/workflows/deploy-dev.yml @@ -1,4 +1,4 @@ -name: beanstalk-springboot-deploy +name: dev-beanstalk-springboot-deploy on: push: diff --git a/.github/workflows/deploy-prod.yml b/.github/workflows/deploy-prod.yml index 6faf535..1268bec 100644 --- a/.github/workflows/deploy-prod.yml +++ b/.github/workflows/deploy-prod.yml @@ -1,4 +1,4 @@ -name: beanstalk-springboot-deploy +name: prod-beanstalk-springboot-deploy on: push: diff --git a/src/main/java/com/tikitaka/naechinso/domain/member/MemberController.java b/src/main/java/com/tikitaka/naechinso/domain/member/MemberController.java new file mode 100644 index 0000000..794b8fc --- /dev/null +++ b/src/main/java/com/tikitaka/naechinso/domain/member/MemberController.java @@ -0,0 +1,34 @@ +package com.tikitaka.naechinso.domain.member; + +import com.tikitaka.naechinso.global.config.CommonApiResponse; +import lombok.RequiredArgsConstructor; +import org.springframework.stereotype.Controller; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.RestController; + +@Controller +@RestController("/member") +@RequiredArgsConstructor +public class MemberController { + + private final MemberService memberService; + + @GetMapping("/save") + public CommonApiResponse saveMember() { + final Long a = memberService.saveMember(); + return CommonApiResponse.of(a); + } + + @GetMapping("/save-detail") + public CommonApiResponse saveMemberWithDetail() { + final Long a = memberService.saveMemberWithDetail(); + return CommonApiResponse.of(a); + } + + @GetMapping("/find") + public CommonApiResponse findAllMember() { + final String a = memberService.getMember(); + return CommonApiResponse.of(a); + } + +} diff --git a/src/main/java/com/tikitaka/naechinso/domain/member/MemberDetailRepository.java b/src/main/java/com/tikitaka/naechinso/domain/member/MemberDetailRepository.java new file mode 100644 index 0000000..dca741d --- /dev/null +++ b/src/main/java/com/tikitaka/naechinso/domain/member/MemberDetailRepository.java @@ -0,0 +1,9 @@ +package com.tikitaka.naechinso.domain.member; + +import com.tikitaka.naechinso.domain.member.entity.MemberDetail; +import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.stereotype.Repository; + +@Repository +public interface MemberDetailRepository extends JpaRepository { +} diff --git a/src/main/java/com/tikitaka/naechinso/domain/member/MemberRepository.java b/src/main/java/com/tikitaka/naechinso/domain/member/MemberRepository.java new file mode 100644 index 0000000..0ffd0c4 --- /dev/null +++ b/src/main/java/com/tikitaka/naechinso/domain/member/MemberRepository.java @@ -0,0 +1,9 @@ +package com.tikitaka.naechinso.domain.member; + +import com.tikitaka.naechinso.domain.member.entity.Member; +import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.stereotype.Repository; + +@Repository +public interface MemberRepository extends JpaRepository { +} diff --git a/src/main/java/com/tikitaka/naechinso/domain/member/MemberService.java b/src/main/java/com/tikitaka/naechinso/domain/member/MemberService.java new file mode 100644 index 0000000..a2e8c23 --- /dev/null +++ b/src/main/java/com/tikitaka/naechinso/domain/member/MemberService.java @@ -0,0 +1,76 @@ +package com.tikitaka.naechinso.domain.member; + +import com.tikitaka.naechinso.domain.member.entity.Member; +import com.tikitaka.naechinso.domain.member.entity.MemberDetail; +import lombok.RequiredArgsConstructor; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +@Service +@RequiredArgsConstructor +@Transactional +public class MemberService { + + private final MemberRepository memberRepository; + private final MemberDetailRepository memberDetailRepository; + + public Long saveMember() { + Member member = Member.builder() + .age(25) + .name("갱미니") + .phone("01012345678") + .build(); + + memberRepository.save(member); + + return member.getId(); + } + + public Long saveMemberWithDetail() { + + + Member recommender = Member.builder() + .age(25) + .name("추천인") + .phone("01012345678") + .build(); + + memberRepository.save(recommender); + + System.out.println("recommender = " + recommender); + + + + Member member = Member.builder() + .age(25) + .name("갱미니") + .phone("01099999999") + .build(); + + System.out.println("member = " + member); + + memberRepository.save(member); + + + MemberDetail memberDetail = MemberDetail.builder() + .height(185) + .mbti("INFP") + .address("서울") + .member(member) + .build(); + + memberDetailRepository.save(memberDetail); + + + System.out.println("memberDetail = " + memberDetail); + + + + return member.getId(); + } + + public String getMember() { + return memberRepository.findAll().toString(); + } + +} diff --git a/src/main/java/com/tikitaka/naechinso/domain/member/entity/Member.java b/src/main/java/com/tikitaka/naechinso/domain/member/entity/Member.java new file mode 100644 index 0000000..6bb223e --- /dev/null +++ b/src/main/java/com/tikitaka/naechinso/domain/member/entity/Member.java @@ -0,0 +1,85 @@ +package com.tikitaka.naechinso.domain.member.entity; + +import com.fasterxml.jackson.annotation.JsonManagedReference; +import com.tikitaka.naechinso.global.config.entity.BaseEntity; +import com.tikitaka.naechinso.global.config.entity.BaseTimeEntity; +import lombok.*; + +import javax.persistence.*; +import java.util.ArrayList; +import java.util.List; + +/** + * 멤버 공통 정보를 담당하는 엔티티입니다 + * @author gengminy 220924 + * */ +@Entity +@Table(name = "member") +@Getter +@Builder +@AllArgsConstructor +@NoArgsConstructor +@ToString +@EqualsAndHashCode +public class Member extends BaseEntity { + + @Id + @Column(name = "mem_id") + @GeneratedValue + private Long id; + + @Column(name = "mem_phone") + private String phone; + + @Column(name = "mem_name") + private String name; + + @Column(name = "mem_sex") + private String sex; + + @Column(name = "mem_age") + private int age; + + @Column(name = "mem_service_yn") + @Builder.Default + private boolean service_yn = false; + + @Column(name = "mem_info_yn") + @Builder.Default + private boolean info_yn = false; + + @Column(name = "mem_religion_yn") + @Builder.Default + private boolean religion_yn = false; + + @Column(name = "mem_location_yn") + @Builder.Default + private boolean location_yn = false; + + @Column(name = "mem_marketing_yn") + @Builder.Default + private boolean marketing_yn = false; + + @Column(name = "mem_job_name") + private String jobName; + + @Column(name = "mem_job_part") + private String jobPart; + + @Column(name = "mem_job_location") + private String jobLocation; + + //가입했을 경우 정보 디테일 + @OneToOne(mappedBy = "member") + @JoinColumn(name = "mem_detail") + private MemberDetail detail; + + + + +// //소개해준 사람들 +// @OneToMany +// @JoinColumn +// @Builder.Default +// private List receivers = new ArrayList<>(); +} diff --git a/src/main/java/com/tikitaka/naechinso/domain/member/entity/MemberDetail.java b/src/main/java/com/tikitaka/naechinso/domain/member/entity/MemberDetail.java new file mode 100644 index 0000000..43d618a --- /dev/null +++ b/src/main/java/com/tikitaka/naechinso/domain/member/entity/MemberDetail.java @@ -0,0 +1,82 @@ +package com.tikitaka.naechinso.domain.member.entity; + +import com.tikitaka.naechinso.global.config.entity.BaseEntity; +import com.tikitaka.naechinso.global.config.entity.BaseTimeEntity; +import lombok.*; + +import javax.persistence.*; + +/** + * 추천 받은 멤버 가입 정보를 담당하는 엔티티입니다 + * @author gengminy 220924 + * */ +@Entity +@Table(name = "member_detail") +@Getter +@Builder +@AllArgsConstructor +@NoArgsConstructor +@ToString(exclude = {"member"}) +@EqualsAndHashCode(exclude = {"member"}) //one to one cycle hashcode 방지 +public class MemberDetail extends BaseEntity { + // member_detail_id => mem_id + @Id + @Column(name = "mem_id") + private Long id; + +// //추천해준 사람의 PK +// @ManyToOne +// @JoinColumn(name = "mem_id2") +// private Member recommender; + + @Column(name = "mem_height") + private int height; + + @Column(name = "mem_address") + private String address; + + @Column(name = "mem_religion") + private String religion; + + @Column(name = "mem_drink") + private String drink; + + @Column(name = "mem_smoke") + private String smoke; + + @Column(name = "mem_mbti") + @Builder.Default + private String mbti = ""; + + @Column(name = "mem_personality") + private String personality; + + @Column(name = "mem_introduce") + @Builder.Default + private String introduce = ""; + + @Column(name = "mem_picture") + private String picture; + + @Column(name = "mem_point") + private Long point; + + @Column(name = "mem_school") + private String school; + + @Column(name = "mem_major") + private String major; + + @Column(name = "mem_edu_level") + private String eduLevel; + + + + + // Member Entity 와 1:1 조인 + // Member PK 그대로 사용 + @OneToOne(cascade = CascadeType.ALL, fetch = FetchType.LAZY) + @MapsId + @JoinColumn(name = "mem_id") + private Member member; +} diff --git a/src/main/java/com/tikitaka/naechinso/domain/point/PointController.java b/src/main/java/com/tikitaka/naechinso/domain/point/PointController.java new file mode 100644 index 0000000..e7372d3 --- /dev/null +++ b/src/main/java/com/tikitaka/naechinso/domain/point/PointController.java @@ -0,0 +1,7 @@ +package com.tikitaka.naechinso.domain.point; + +import org.springframework.stereotype.Controller; + +@Controller +public class PointController { +} diff --git a/src/main/java/com/tikitaka/naechinso/domain/point/PointRepository.java b/src/main/java/com/tikitaka/naechinso/domain/point/PointRepository.java new file mode 100644 index 0000000..55501bf --- /dev/null +++ b/src/main/java/com/tikitaka/naechinso/domain/point/PointRepository.java @@ -0,0 +1,4 @@ +package com.tikitaka.naechinso.domain.point; + +public interface PointRepository { +} diff --git a/src/main/java/com/tikitaka/naechinso/domain/point/PointService.java b/src/main/java/com/tikitaka/naechinso/domain/point/PointService.java new file mode 100644 index 0000000..0f65b5b --- /dev/null +++ b/src/main/java/com/tikitaka/naechinso/domain/point/PointService.java @@ -0,0 +1,7 @@ +package com.tikitaka.naechinso.domain.point; + +import org.springframework.stereotype.Service; + +@Service +public class PointService { +} diff --git a/src/main/java/com/tikitaka/naechinso/domain/point/entity/Point.java b/src/main/java/com/tikitaka/naechinso/domain/point/entity/Point.java new file mode 100644 index 0000000..21e168e --- /dev/null +++ b/src/main/java/com/tikitaka/naechinso/domain/point/entity/Point.java @@ -0,0 +1,41 @@ +package com.tikitaka.naechinso.domain.point.entity; + +import com.tikitaka.naechinso.domain.member.entity.Member; +import com.tikitaka.naechinso.domain.member.entity.MemberDetail; +import com.tikitaka.naechinso.global.config.entity.BaseEntity; +import com.tikitaka.naechinso.global.config.entity.BaseTimeEntity; +import lombok.*; + +import javax.persistence.*; + +/** + * 포인트 충전 및 사용 정보를 담당하는 엔티티입니다 + * @author gengminy 220924 + * */ +@Entity +@Table(name = "point") +@Getter +@Builder +@AllArgsConstructor +@NoArgsConstructor +@ToString +public class Point extends BaseEntity { + @Id + @GeneratedValue + @Column(name = "poi_id") + private Long id; + + @Column(name = "poi_value") + private Long value; + + @Column(name = "poi_content") + private String content; + + @Column(name = "poi_type") + private String type; + +// +// @ManyToOne +// @PrimaryKeyJoinColumn +// private Member member; +} diff --git a/src/main/java/com/tikitaka/naechinso/domain/recommend/RecommendController.java b/src/main/java/com/tikitaka/naechinso/domain/recommend/RecommendController.java new file mode 100644 index 0000000..fd454c6 --- /dev/null +++ b/src/main/java/com/tikitaka/naechinso/domain/recommend/RecommendController.java @@ -0,0 +1,7 @@ +package com.tikitaka.naechinso.domain.recommend; + +import org.springframework.stereotype.Controller; + +@Controller +public class RecommendController { +} diff --git a/src/main/java/com/tikitaka/naechinso/domain/recommend/RecommendRepository.java b/src/main/java/com/tikitaka/naechinso/domain/recommend/RecommendRepository.java new file mode 100644 index 0000000..fb80185 --- /dev/null +++ b/src/main/java/com/tikitaka/naechinso/domain/recommend/RecommendRepository.java @@ -0,0 +1,4 @@ +package com.tikitaka.naechinso.domain.recommend; + +public interface RecommendRepository { +} diff --git a/src/main/java/com/tikitaka/naechinso/domain/recommend/RecommendService.java b/src/main/java/com/tikitaka/naechinso/domain/recommend/RecommendService.java new file mode 100644 index 0000000..42c1315 --- /dev/null +++ b/src/main/java/com/tikitaka/naechinso/domain/recommend/RecommendService.java @@ -0,0 +1,7 @@ +package com.tikitaka.naechinso.domain.recommend; + +import org.springframework.stereotype.Service; + +@Service +public class RecommendService { +} diff --git a/src/main/java/com/tikitaka/naechinso/domain/recommend/entity/Recommend.java b/src/main/java/com/tikitaka/naechinso/domain/recommend/entity/Recommend.java new file mode 100644 index 0000000..7fe04cb --- /dev/null +++ b/src/main/java/com/tikitaka/naechinso/domain/recommend/entity/Recommend.java @@ -0,0 +1,26 @@ +package com.tikitaka.naechinso.domain.recommend.entity; + +import com.tikitaka.naechinso.global.config.entity.BaseEntity; +import com.tikitaka.naechinso.global.config.entity.BaseTimeEntity; +import lombok.*; + +import javax.persistence.*; + +/** + * 추천사 정보를 담당하는 엔티티입니다 + * @author gengminy 220924 + * */ +@Entity +@Table(name = "recommend") +@Getter +@Builder +@AllArgsConstructor +@NoArgsConstructor +@ToString +public class Recommend extends BaseEntity { + + @Id + @GeneratedValue + @Column(name = "rec_id") + private Long id; +} diff --git a/src/main/java/com/tikitaka/naechinso/global/config/entity/BaseEntity.java b/src/main/java/com/tikitaka/naechinso/global/config/entity/BaseEntity.java index 0b8b577..072c2f1 100644 --- a/src/main/java/com/tikitaka/naechinso/global/config/entity/BaseEntity.java +++ b/src/main/java/com/tikitaka/naechinso/global/config/entity/BaseEntity.java @@ -6,13 +6,12 @@ import javax.persistence.*; -/** 상속받으면 생성시간 업데이트시간 - * 생성한 사람, 업데이트한 사람 필드 자동으로 만들어주는 엔티티입니다 +/** 상속받으면 createdAt, updatedAt, delStatus 자동으로 만들어주는 엔티티입니다 * jpa의 audit(감시) 기능을 사용합니다 */ @MappedSuperclass @EntityListeners({ AuditingEntityListener.class }) @Getter -public class BaseEntity { +public class BaseEntity extends BaseTimeEntity { @Enumerated(EnumType.STRING) @Column(columnDefinition = "Text default 'N'") private DeleteStatus delStatus=DeleteStatus.N; diff --git a/src/main/java/com/tikitaka/naechinso/global/config/entity/BaseTimeEntity.java b/src/main/java/com/tikitaka/naechinso/global/config/entity/BaseTimeEntity.java index e68a448..fcea938 100644 --- a/src/main/java/com/tikitaka/naechinso/global/config/entity/BaseTimeEntity.java +++ b/src/main/java/com/tikitaka/naechinso/global/config/entity/BaseTimeEntity.java @@ -10,12 +10,13 @@ import javax.persistence.MappedSuperclass; import java.time.LocalDateTime; -/** 상속받으면 createdAt, updatedAt 필드 자동으로 만들어주는 엔티티입니다 +/** 상속받으면 createdAt, updatedAt + * 필드 자동으로 만들어주는 엔티티입니다 * jpa의 audit(감시) 기능을 사용합니다 */ @MappedSuperclass @EntityListeners({ AuditingEntityListener.class }) @Getter -public class BaseTimeEntity extends BaseEntity{ +public class BaseTimeEntity { @CreatedDate @Column(updatable = false) private LocalDateTime createdAt; From f6ec9c873fd1928368020aaca111a66dc4544edd Mon Sep 17 00:00:00 2001 From: gengminy Date: Sat, 24 Sep 2022 22:31:39 +0900 Subject: [PATCH 02/72] =?UTF-8?q?:rocket:=20feat(user):=20=ED=9A=8C?= =?UTF-8?q?=EC=9B=90=EA=B0=80=EC=9E=85=20=EA=B5=AC=ED=98=84=20=EB=B0=8F=20?= =?UTF-8?q?Enum=20Validator=20=EC=B6=94=EA=B0=80=20#18?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../domain/member/MemberController.java | 63 +++++++++---- .../domain/member/MemberRepository.java | 4 + .../domain/member/MemberService.java | 94 ++++++++++--------- .../domain/member/constant/Gender.java | 19 ++++ .../dto/MemberCommonJoinRequestDto.java | 80 ++++++++++++++++ .../dto/MemberCommonJoinResponseDto.java | 40 ++++++++ .../dto/MemberDetailJoinRequestDto.java | 78 +++++++++++++++ .../domain/member/entity/Member.java | 30 +++--- .../domain/member/entity/MemberDetail.java | 2 +- .../sms/SmsCertificationController.java | 2 +- .../sms/SmsCertificationServiceImpl.java | 26 +++-- .../global/annotation/AuthMember.java | 14 +++ .../naechinso/global/annotation/Enum.java | 21 +++++ .../global/annotation/EnumValidator.java | 30 ++++++ .../config/security/LoginServiceImpl.java | 38 ++++++++ .../global/config/security/UserAccount.java | 20 ++++ .../config/security/jwt/JwtTokenProvider.java | 4 +- .../global/error/GlobalExceptionHandler.java | 2 +- 18 files changed, 477 insertions(+), 90 deletions(-) create mode 100644 src/main/java/com/tikitaka/naechinso/domain/member/constant/Gender.java create mode 100644 src/main/java/com/tikitaka/naechinso/domain/member/dto/MemberCommonJoinRequestDto.java create mode 100644 src/main/java/com/tikitaka/naechinso/domain/member/dto/MemberCommonJoinResponseDto.java create mode 100644 src/main/java/com/tikitaka/naechinso/domain/member/dto/MemberDetailJoinRequestDto.java create mode 100644 src/main/java/com/tikitaka/naechinso/global/annotation/AuthMember.java create mode 100644 src/main/java/com/tikitaka/naechinso/global/annotation/Enum.java create mode 100644 src/main/java/com/tikitaka/naechinso/global/annotation/EnumValidator.java create mode 100644 src/main/java/com/tikitaka/naechinso/global/config/security/LoginServiceImpl.java create mode 100644 src/main/java/com/tikitaka/naechinso/global/config/security/UserAccount.java diff --git a/src/main/java/com/tikitaka/naechinso/domain/member/MemberController.java b/src/main/java/com/tikitaka/naechinso/domain/member/MemberController.java index 794b8fc..156a7ef 100644 --- a/src/main/java/com/tikitaka/naechinso/domain/member/MemberController.java +++ b/src/main/java/com/tikitaka/naechinso/domain/member/MemberController.java @@ -1,34 +1,63 @@ package com.tikitaka.naechinso.domain.member; +import com.tikitaka.naechinso.domain.member.dto.MemberCommonJoinRequestDto; +import com.tikitaka.naechinso.domain.member.dto.MemberCommonJoinResponseDto; +import com.tikitaka.naechinso.domain.member.entity.Member; +import com.tikitaka.naechinso.global.annotation.AuthMember; import com.tikitaka.naechinso.global.config.CommonApiResponse; +import com.tikitaka.naechinso.global.error.ErrorCode; +import com.tikitaka.naechinso.global.error.exception.UnauthorizedException; +import io.swagger.annotations.ApiOperation; +import io.swagger.annotations.ApiParam; +import io.swagger.annotations.Authorization; +import io.swagger.v3.oas.annotations.Hidden; +import io.swagger.v3.oas.annotations.Parameter; import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.springframework.security.core.annotation.AuthenticationPrincipal; import org.springframework.stereotype.Controller; -import org.springframework.web.bind.annotation.GetMapping; -import org.springframework.web.bind.annotation.RestController; +import org.springframework.web.bind.annotation.*; +import springfox.documentation.annotations.ApiIgnore; -@Controller -@RestController("/member") +import javax.servlet.http.HttpServletRequest; +import javax.validation.Valid; + +@Slf4j +@RestController +@RequestMapping("/member") @RequiredArgsConstructor public class MemberController { private final MemberService memberService; - @GetMapping("/save") - public CommonApiResponse saveMember() { - final Long a = memberService.saveMember(); - return CommonApiResponse.of(a); - } + @GetMapping("/") + @ApiOperation(value = "유저 자신의 정보를 가져온다 (AccessToken 필요)") + public CommonApiResponse getMyInformation(HttpServletRequest request, @ApiIgnore @AuthMember Member member) { + System.out.println("member = " + member);/// + - @GetMapping("/save-detail") - public CommonApiResponse saveMemberWithDetail() { - final Long a = memberService.saveMemberWithDetail(); - return CommonApiResponse.of(a); + if (member == null) { + throw new UnauthorizedException(ErrorCode.UNAUTHORIZED_USER); + } + + return CommonApiResponse.of(MemberCommonJoinResponseDto.of(member)); } - @GetMapping("/find") - public CommonApiResponse findAllMember() { - final String a = memberService.getMember(); - return CommonApiResponse.of(a); + + + @PostMapping("/join") + public CommonApiResponse joinCommonMember(@Valid @RequestBody MemberCommonJoinRequestDto dto) { + final MemberCommonJoinResponseDto res = memberService.joinCommonMember(dto); + return CommonApiResponse.of(res); } +// @PostMapping("/login") + + +// @GetMapping("/find") +// public CommonApiResponse findAllMember() { +// final String a = memberService.getMember(); +// return CommonApiResponse.of(a); +// } + } diff --git a/src/main/java/com/tikitaka/naechinso/domain/member/MemberRepository.java b/src/main/java/com/tikitaka/naechinso/domain/member/MemberRepository.java index 0ffd0c4..09dbc90 100644 --- a/src/main/java/com/tikitaka/naechinso/domain/member/MemberRepository.java +++ b/src/main/java/com/tikitaka/naechinso/domain/member/MemberRepository.java @@ -4,6 +4,10 @@ import org.springframework.data.jpa.repository.JpaRepository; import org.springframework.stereotype.Repository; +import java.util.Optional; + @Repository public interface MemberRepository extends JpaRepository { + + Optional findByPhone(String phone); } diff --git a/src/main/java/com/tikitaka/naechinso/domain/member/MemberService.java b/src/main/java/com/tikitaka/naechinso/domain/member/MemberService.java index a2e8c23..aeb587a 100644 --- a/src/main/java/com/tikitaka/naechinso/domain/member/MemberService.java +++ b/src/main/java/com/tikitaka/naechinso/domain/member/MemberService.java @@ -1,11 +1,23 @@ package com.tikitaka.naechinso.domain.member; +import com.tikitaka.naechinso.domain.member.dto.MemberCommonJoinRequestDto; +import com.tikitaka.naechinso.domain.member.dto.MemberCommonJoinResponseDto; import com.tikitaka.naechinso.domain.member.entity.Member; import com.tikitaka.naechinso.domain.member.entity.MemberDetail; +import com.tikitaka.naechinso.global.common.response.TokenResponseDTO; +import com.tikitaka.naechinso.global.config.security.dto.JwtDTO; +import com.tikitaka.naechinso.global.config.security.jwt.JwtTokenProvider; +import com.tikitaka.naechinso.global.error.ErrorCode; +import com.tikitaka.naechinso.global.error.exception.BadRequestException; import lombok.RequiredArgsConstructor; +import org.springframework.security.authentication.UsernamePasswordAuthenticationToken; +import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder; +import org.springframework.security.core.Authentication; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; +import java.util.Optional; + @Service @RequiredArgsConstructor @Transactional @@ -13,64 +25,62 @@ public class MemberService { private final MemberRepository memberRepository; private final MemberDetailRepository memberDetailRepository; + private final AuthenticationManagerBuilder authenticationManagerBuilder; + private final JwtTokenProvider jwtTokenProvider; + + public MemberCommonJoinResponseDto joinCommonMember(MemberCommonJoinRequestDto dto) { - public Long saveMember() { - Member member = Member.builder() - .age(25) - .name("갱미니") - .phone("01012345678") - .build(); + //이미 존재하는 유저일 경우 400 + Optional checkMember = memberRepository.findByPhone(dto.getPhone()); + if(!checkMember.isEmpty()) { + throw new BadRequestException(ErrorCode.USER_ALREADY_EXIST); + } + Member member = MemberCommonJoinRequestDto.toCommonMember(dto); memberRepository.save(member); - return member.getId(); + MemberCommonJoinResponseDto res = MemberCommonJoinResponseDto.of(member); + return res; } - public Long saveMemberWithDetail() { - - - Member recommender = Member.builder() - .age(25) - .name("추천인") - .phone("01012345678") - .build(); - - memberRepository.save(recommender); - - System.out.println("recommender = " + recommender); + public TokenResponseDTO login(String phone) { + System.out.println("phone = " + phone); + UsernamePasswordAuthenticationToken authenticationToken + = new UsernamePasswordAuthenticationToken(phone, null); - Member member = Member.builder() - .age(25) - .name("갱미니") - .phone("01099999999") - .build(); + // 2. 실제로 검증 (사용자 비밀번호 체크) 이 이루어지는 부분 + // authenticate 메서드가 실행이 될 때 + // LoginServiceImpl의 loadUserByUsername 메서드가 실행됨 + Authentication authentication + = authenticationManagerBuilder.getObject().authenticate(authenticationToken); - System.out.println("member = " + member); - memberRepository.save(member); - - - MemberDetail memberDetail = MemberDetail.builder() - .height(185) - .mbti("INFP") - .address("서울") - .member(member) - .build(); - memberDetailRepository.save(memberDetail); + System.out.println("1 = " + 1); + TokenResponseDTO tokenResponseDTO + = jwtTokenProvider.generateToken(new JwtDTO(phone)); - System.out.println("memberDetail = " + memberDetail); + System.out.println("2 = " + 2); - - - return member.getId(); + return tokenResponseDTO; } - public String getMember() { - return memberRepository.findAll().toString(); - } +// +// public MemberCommonJoinResponseDto joinMemberWithDetail(MemberCommonJoinRequestDto dto) { +// //이미 존재하는 유저일 경우 400 +// Optional checkMember = memberRepository.findByPhone(dto.getPhone()); +// if(!checkMember.isEmpty()) { +// throw new BadRequestException(ErrorCode.USER_ALREADY_EXIST); +// } +// +// Member member = MemberCommonJoinRequestDto.toCommonMember(dto); +// memberRepository.save(member); +// +// MemberCommonJoinResponseDto res = MemberCommonJoinResponseDto.of(member); +// return res; +// } } diff --git a/src/main/java/com/tikitaka/naechinso/domain/member/constant/Gender.java b/src/main/java/com/tikitaka/naechinso/domain/member/constant/Gender.java new file mode 100644 index 0000000..251a8e2 --- /dev/null +++ b/src/main/java/com/tikitaka/naechinso/domain/member/constant/Gender.java @@ -0,0 +1,19 @@ +package com.tikitaka.naechinso.domain.member.constant; + +import com.fasterxml.jackson.annotation.JsonCreator; + +public enum Gender { + M, + W; + + //Enum Validation 을 위한 코드, enum 에 속하지 않으면 null 리턴 + @JsonCreator + public static Gender fromGender(String val){ + for(Gender gender : Gender.values()){ + if(gender.name().equals(val)){ + return gender; + } + } + return null; + } +} diff --git a/src/main/java/com/tikitaka/naechinso/domain/member/dto/MemberCommonJoinRequestDto.java b/src/main/java/com/tikitaka/naechinso/domain/member/dto/MemberCommonJoinRequestDto.java new file mode 100644 index 0000000..46cba24 --- /dev/null +++ b/src/main/java/com/tikitaka/naechinso/domain/member/dto/MemberCommonJoinRequestDto.java @@ -0,0 +1,80 @@ +package com.tikitaka.naechinso.domain.member.dto; + +import com.tikitaka.naechinso.domain.member.constant.Gender; +import com.tikitaka.naechinso.domain.member.entity.Member; +import com.tikitaka.naechinso.global.annotation.Enum; +import lombok.*; +import org.hibernate.validator.constraints.Length; + +import javax.validation.constraints.*; + +/** + * 추천인 및 추천 받는 사람 공통 가입을 위한 Dto입니다 + * @author gengminy 220924 + * */ +@AllArgsConstructor +@NoArgsConstructor +@Getter +@Builder +@ToString +public class MemberCommonJoinRequestDto { + @NotBlank(message = "전화번호를 입력해주세요") + @Pattern(regexp = "[0-9]{10,11}", message = "하이픈 없는 10~11자리 숫자를 입력해주세요") + private String phone; + + @NotBlank(message = "이름을 입력해주세요") + private String name; + + @Enum(enumClass = Gender.class, message = "성별 입력이 올바르지 않습니다. M 또는 W가 필요합니다") + private Gender gender; + + @Min(value = 25, message = "25-33세까지만 가입 가능합니다") + @Max(value = 33, message = "25-33세까지만 가입 가능합니다") + private int age; + + @NotNull(message = "서비스 이용약관 동의가 필요합니다") + @AssertTrue(message = "서비스 이용약관 동의가 필요합니다") + private boolean acceptsService; + + @NotNull(message = "개인정보 이용 동의가 필요합니다") + @AssertTrue(message = "개인정보 이용 동의가 필요합니다") + private boolean acceptsInfo; + + @NotNull(message = "종교 정보 제공 동의가 필요합니다") + @AssertTrue(message = "종교 정보 제공 동의가 필요합니다") + private boolean acceptsReligion; + + @NotNull(message = "위치 정보 제공 동의 여부가 필요합니다") + private boolean acceptsLocation; + + @NotNull(message = "마케팅 동의 여부가 필요합니다") + private boolean acceptsMarketing; + + @NotBlank(message = "직장명을 입력해주세요") + private String jobName; + + @NotBlank(message = "직장 부서를 입력해주세요") + private String jobPart; + + @NotBlank(message = "직장 위치를 입력해주세요") + private String jobLocation; + + public static Member toCommonMember(MemberCommonJoinRequestDto dto) { + Member member = Member.builder() + .phone(dto.phone) + .name(dto.name) + .gender(dto.gender) + .age(dto.age) + .acceptsService(dto.acceptsService) + .acceptsInfo(dto.acceptsInfo) + .acceptsReligion(dto.acceptsReligion) + .acceptsLocation(dto.acceptsLocation) + .acceptsMarketing(dto.acceptsMarketing) + .jobName(dto.jobName) + .jobPart(dto.jobPart) + .jobLocation(dto.jobLocation) + .build(); + + return member; + } +} diff --git a/src/main/java/com/tikitaka/naechinso/domain/member/dto/MemberCommonJoinResponseDto.java b/src/main/java/com/tikitaka/naechinso/domain/member/dto/MemberCommonJoinResponseDto.java new file mode 100644 index 0000000..09945ae --- /dev/null +++ b/src/main/java/com/tikitaka/naechinso/domain/member/dto/MemberCommonJoinResponseDto.java @@ -0,0 +1,40 @@ +package com.tikitaka.naechinso.domain.member.dto; + +import com.tikitaka.naechinso.domain.member.constant.Gender; +import com.tikitaka.naechinso.domain.member.entity.Member; +import lombok.*; + +import javax.validation.constraints.NotBlank; +import javax.validation.constraints.NotNull; +import javax.validation.constraints.Pattern; +import javax.validation.constraints.Size; + +/** + * 추천인 및 추천 받는 사람 공통 가입을 위한 Dto입니다 + * @author gengminy 220924 + * */ +@AllArgsConstructor +@NoArgsConstructor +@Getter +@Builder +@ToString +public class MemberCommonJoinResponseDto { + private String phone; + + private String name; + + private Gender gender; + + private int age; + + public static MemberCommonJoinResponseDto of(Member member) { + MemberCommonJoinResponseDto res = MemberCommonJoinResponseDto.builder() + .phone(member.getPhone()) + .name(member.getName()) + .gender(member.getGender()) + .age(member.getAge()) + .build(); + + return res; + } +} diff --git a/src/main/java/com/tikitaka/naechinso/domain/member/dto/MemberDetailJoinRequestDto.java b/src/main/java/com/tikitaka/naechinso/domain/member/dto/MemberDetailJoinRequestDto.java new file mode 100644 index 0000000..be122c5 --- /dev/null +++ b/src/main/java/com/tikitaka/naechinso/domain/member/dto/MemberDetailJoinRequestDto.java @@ -0,0 +1,78 @@ +package com.tikitaka.naechinso.domain.member.dto; + +import com.tikitaka.naechinso.domain.member.constant.Gender; +import com.tikitaka.naechinso.domain.member.entity.Member; +import lombok.*; + +import javax.validation.constraints.*; + +/** + * 추천 받은 사람의 가입을 위한 Dto입니다 + * @author gengminy 220924 + * */ +@AllArgsConstructor +@NoArgsConstructor +@Getter +@Builder +@ToString +public class MemberDetailJoinRequestDto { + @NotBlank(message = "전화번호를 입력해주세요") + @Pattern(regexp = "[0-9]{10,11}", message = "하이픈 없는 10~11자리 숫자를 입력해주세요") + private String phone; + + @NotBlank(message = "이름을 입력해주세요") + private String name; + + @NotNull(message = "성별을 입력해주세요") + private Gender gender; + + @Min(value = 25, message = "25-33세까지만 가입 가능합니다") + @Max(value = 33, message = "25-33세까지만 가입 가능합니다") + private int age; + + @NotNull(message = "서비스 이용약관 동의가 필요합니다") + @AssertTrue(message = "서비스 이용약관 동의가 필요합니다") + private boolean acceptsService; + + @NotNull(message = "개인정보 이용 동의가 필요합니다") + @AssertTrue(message = "개인정보 이용 동의가 필요합니다") + private boolean acceptsInfo; + + @NotNull(message = "종교 정보 제공 동의가 필요합니다") + @AssertTrue(message = "종교 정보 제공 동의가 필요합니다") + private boolean acceptsReligion; + + @NotNull(message = "위치 정보 제공 동의 여부가 필요합니다") + private boolean acceptsLocation; + + @NotNull(message = "마케팅 동의 여부가 필요합니다") + private boolean acceptsMarketing; + + @NotBlank(message = "직장명을 입력해주세요") + private String jobName; + + @NotBlank(message = "직장 부서를 입력해주세요") + private String jobPart; + + @NotBlank(message = "직장 위치를 입력해주세요") + private String jobLocation; + + public static Member toCommonMember(MemberDetailJoinRequestDto dto) { + Member member = Member.builder() + .phone(dto.phone) + .name(dto.name) + .gender(dto.gender) + .age(dto.age) + .acceptsService(dto.acceptsService) + .acceptsInfo(dto.acceptsInfo) + .acceptsReligion(dto.acceptsReligion) + .acceptsLocation(dto.acceptsLocation) + .acceptsMarketing(dto.acceptsMarketing) + .jobName(dto.jobName) + .jobPart(dto.jobPart) + .jobLocation(dto.jobLocation) + .build(); + + return member; + } +} diff --git a/src/main/java/com/tikitaka/naechinso/domain/member/entity/Member.java b/src/main/java/com/tikitaka/naechinso/domain/member/entity/Member.java index 6bb223e..dcea98c 100644 --- a/src/main/java/com/tikitaka/naechinso/domain/member/entity/Member.java +++ b/src/main/java/com/tikitaka/naechinso/domain/member/entity/Member.java @@ -1,13 +1,10 @@ package com.tikitaka.naechinso.domain.member.entity; -import com.fasterxml.jackson.annotation.JsonManagedReference; +import com.tikitaka.naechinso.domain.member.constant.Gender; import com.tikitaka.naechinso.global.config.entity.BaseEntity; -import com.tikitaka.naechinso.global.config.entity.BaseTimeEntity; import lombok.*; import javax.persistence.*; -import java.util.ArrayList; -import java.util.List; /** * 멤버 공통 정보를 담당하는 엔티티입니다 @@ -34,31 +31,32 @@ public class Member extends BaseEntity { @Column(name = "mem_name") private String name; - @Column(name = "mem_sex") - private String sex; + @Column(name = "mem_gender") + @Enumerated(EnumType.STRING) + private Gender gender; @Column(name = "mem_age") private int age; - @Column(name = "mem_service_yn") + @Column(name = "mem_accpets_service") @Builder.Default - private boolean service_yn = false; + private boolean acceptsService = false; - @Column(name = "mem_info_yn") + @Column(name = "mem_accpets_info") @Builder.Default - private boolean info_yn = false; + private boolean acceptsInfo = false; - @Column(name = "mem_religion_yn") + @Column(name = "mem_accpets_religion") @Builder.Default - private boolean religion_yn = false; + private boolean acceptsReligion = false; - @Column(name = "mem_location_yn") + @Column(name = "mem_accpets_location") @Builder.Default - private boolean location_yn = false; + private boolean acceptsLocation = false; - @Column(name = "mem_marketing_yn") + @Column(name = "mem_accpets_marketing") @Builder.Default - private boolean marketing_yn = false; + private boolean acceptsMarketing = false; @Column(name = "mem_job_name") private String jobName; diff --git a/src/main/java/com/tikitaka/naechinso/domain/member/entity/MemberDetail.java b/src/main/java/com/tikitaka/naechinso/domain/member/entity/MemberDetail.java index 43d618a..7caf770 100644 --- a/src/main/java/com/tikitaka/naechinso/domain/member/entity/MemberDetail.java +++ b/src/main/java/com/tikitaka/naechinso/domain/member/entity/MemberDetail.java @@ -30,7 +30,7 @@ public class MemberDetail extends BaseEntity { // private Member recommender; @Column(name = "mem_height") - private int height; + private Integer height; @Column(name = "mem_address") private String address; diff --git a/src/main/java/com/tikitaka/naechinso/domain/sms/SmsCertificationController.java b/src/main/java/com/tikitaka/naechinso/domain/sms/SmsCertificationController.java index 51657e6..b3dab7b 100644 --- a/src/main/java/com/tikitaka/naechinso/domain/sms/SmsCertificationController.java +++ b/src/main/java/com/tikitaka/naechinso/domain/sms/SmsCertificationController.java @@ -21,7 +21,7 @@ public class SmsCertificationController { private final SmsCertificationService smsCertificationService; @PostMapping("/send") - public CommonApiResponse sendMessageWithVerificationCode( @Valid @RequestBody SmsVerificationCodeRequestDTO dto) { + public CommonApiResponse sendMessageWithVerificationCode(@Valid @RequestBody SmsVerificationCodeRequestDTO dto) { String result = smsCertificationService.sendVerificationMessage(dto.getPhoneNumber()); return CommonApiResponse.of(result); } diff --git a/src/main/java/com/tikitaka/naechinso/domain/sms/SmsCertificationServiceImpl.java b/src/main/java/com/tikitaka/naechinso/domain/sms/SmsCertificationServiceImpl.java index 8011186..956327b 100644 --- a/src/main/java/com/tikitaka/naechinso/domain/sms/SmsCertificationServiceImpl.java +++ b/src/main/java/com/tikitaka/naechinso/domain/sms/SmsCertificationServiceImpl.java @@ -1,6 +1,9 @@ package com.tikitaka.naechinso.domain.sms; import com.fasterxml.jackson.databind.ObjectMapper; +import com.tikitaka.naechinso.domain.member.MemberRepository; +import com.tikitaka.naechinso.domain.member.MemberService; +import com.tikitaka.naechinso.domain.member.entity.Member; import com.tikitaka.naechinso.global.common.response.TokenResponseDTO; import com.tikitaka.naechinso.global.config.security.dto.JwtDTO; import com.tikitaka.naechinso.global.config.security.jwt.JwtTokenProvider; @@ -28,6 +31,7 @@ import java.time.Duration; import java.util.ArrayList; import java.util.List; +import java.util.Optional; import java.util.Random; @Slf4j @@ -38,6 +42,8 @@ public class SmsCertificationServiceImpl implements SmsCertificationService { private final SmsService smsService; private final RedisService redisService; private final JwtTokenProvider jwtTokenProvider; + private final MemberRepository memberRepository; + private final MemberService memberService; private final String VERIFICATION_PREFIX = "sms:"; private final int VERIFICATION_TIME_LIMIT = 3 * 60; @@ -104,19 +110,19 @@ public TokenResponseDTO verifyCode(SmsCertificationRequestDTO smsCertificationRe //redis 인증 필터 성공하면 try { - //인증한 휴대폰 번호로 토큰 생성 - TokenResponseDTO tokenResponseDTO - = jwtTokenProvider.generateToken( - /** !!@#!!@#!#!@ 임시 dto 수정 반드시 필요 */ - new JwtDTO(phoneNumber) - ); - - //jwt 생성 하면 모든 로직 종료, redis 에서 전화번호 삭제 redisService.deleteValues(key); - //토큰 반환 - return tokenResponseDTO; + //가입 안된 회원일 경우 null 리턴 + Optional checkMember = memberRepository.findByPhone(phoneNumber); + if (checkMember.isEmpty()) { + return null; + } + + //이미 가입한 회원이면 + //인증한 휴대폰 번호로 로그인 후 토큰 생성 및 반환 + return memberService.login(phoneNumber); } catch (Exception e) { + e.printStackTrace(); throw new InternalServerException("jwt 토큰 생성 에러"); } } diff --git a/src/main/java/com/tikitaka/naechinso/global/annotation/AuthMember.java b/src/main/java/com/tikitaka/naechinso/global/annotation/AuthMember.java new file mode 100644 index 0000000..f331b4a --- /dev/null +++ b/src/main/java/com/tikitaka/naechinso/global/annotation/AuthMember.java @@ -0,0 +1,14 @@ +package com.tikitaka.naechinso.global.annotation; + +import org.springframework.security.core.annotation.AuthenticationPrincipal; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +@Target(ElementType.PARAMETER) +@Retention(RetentionPolicy.RUNTIME) +@AuthenticationPrincipal(expression = "#this == 'anonymousUser ? null : member'") +public @interface AuthMember { +} diff --git a/src/main/java/com/tikitaka/naechinso/global/annotation/Enum.java b/src/main/java/com/tikitaka/naechinso/global/annotation/Enum.java new file mode 100644 index 0000000..eabebdf --- /dev/null +++ b/src/main/java/com/tikitaka/naechinso/global/annotation/Enum.java @@ -0,0 +1,21 @@ +package com.tikitaka.naechinso.global.annotation; + +import javax.validation.Constraint; +import javax.validation.Payload; +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +/* 해당 annotation이 실행 할 ConstraintValidator 구현체를 `EnumValidator`로 지정합니다. */ +@Constraint(validatedBy = {EnumValidator.class}) +/* 해당 annotation은 메소드, 필드, 파라미터에 적용 할 수 있습니다. */ +@Target({ElementType.METHOD, ElementType.FIELD, ElementType.PARAMETER}) +/* annotation을 Runtime까지 유지합니다. */ +@Retention(RetentionPolicy.RUNTIME) +public @interface Enum { + String message() default "Invalid Enum Value. This is not permitted."; + Class[] groups() default {}; + Class[] payload() default {}; + Class> enumClass(); +} diff --git a/src/main/java/com/tikitaka/naechinso/global/annotation/EnumValidator.java b/src/main/java/com/tikitaka/naechinso/global/annotation/EnumValidator.java new file mode 100644 index 0000000..cf06450 --- /dev/null +++ b/src/main/java/com/tikitaka/naechinso/global/annotation/EnumValidator.java @@ -0,0 +1,30 @@ +package com.tikitaka.naechinso.global.annotation; + +import javax.validation.ConstraintValidator; +import javax.validation.ConstraintValidatorContext; + +public class EnumValidator implements ConstraintValidator { + + private Enum annotation; + + @Override + public void initialize(Enum constraintAnnotation) { + this.annotation = constraintAnnotation; + } + + @Override + public boolean isValid(java.lang.Enum value, ConstraintValidatorContext context) { + boolean result = false; + Object[] enumValues = this.annotation.enumClass().getEnumConstants(); + if (enumValues != null) { + for (Object enumValue : enumValues) { + if (value == enumValue) { + result = true; + break; + } + } + } + return result; + } + +} diff --git a/src/main/java/com/tikitaka/naechinso/global/config/security/LoginServiceImpl.java b/src/main/java/com/tikitaka/naechinso/global/config/security/LoginServiceImpl.java new file mode 100644 index 0000000..c4019f5 --- /dev/null +++ b/src/main/java/com/tikitaka/naechinso/global/config/security/LoginServiceImpl.java @@ -0,0 +1,38 @@ +package com.tikitaka.naechinso.global.config.security; + + +import com.tikitaka.naechinso.domain.member.MemberRepository; +import com.tikitaka.naechinso.domain.member.entity.Member; +import lombok.RequiredArgsConstructor; +import org.springframework.security.core.GrantedAuthority; +import org.springframework.security.core.authority.SimpleGrantedAuthority; +import org.springframework.security.core.userdetails.User; +import org.springframework.security.core.userdetails.UserDetails; +import org.springframework.security.core.userdetails.UserDetailsService; +import org.springframework.security.core.userdetails.UsernameNotFoundException; +import org.springframework.stereotype.Service; + +import javax.transaction.Transactional; +import java.util.Collections; +import java.util.Optional; + +@RequiredArgsConstructor +@Service +public class LoginServiceImpl implements UserDetailsService { + + private final MemberRepository memberRepository; + + @Override + @Transactional + public UserDetails loadUserByUsername(String phone) throws UsernameNotFoundException { + Member member = memberRepository.findByPhone(phone) + .orElseThrow(() -> { throw new UsernameNotFoundException(phone + "-> DB에 없는 유저"); }); + + return new UserAccount(member); + } +// +// //DB에 존재하는 유저일 경우 UserDetails로 만들어서 반환 +// private UserDetails createUserDetails(Member member) { +// GrantedAuthority grantedAuthority = new SimpleGrantedAuthority("ROLE_USER"); +// } +} \ No newline at end of file diff --git a/src/main/java/com/tikitaka/naechinso/global/config/security/UserAccount.java b/src/main/java/com/tikitaka/naechinso/global/config/security/UserAccount.java new file mode 100644 index 0000000..6fdac7c --- /dev/null +++ b/src/main/java/com/tikitaka/naechinso/global/config/security/UserAccount.java @@ -0,0 +1,20 @@ +package com.tikitaka.naechinso.global.config.security; + +import com.tikitaka.naechinso.domain.member.entity.Member; +import lombok.Getter; +import org.springframework.security.core.GrantedAuthority; +import org.springframework.security.core.authority.SimpleGrantedAuthority; +import org.springframework.security.core.userdetails.User; + +import java.util.Collection; +import java.util.List; + +@Getter +public class UserAccount extends User { + private Member member; + + public UserAccount(Member member) { + super(member.getPhone(), null, List.of(new SimpleGrantedAuthority("ROLE_USER"))); + this.member = member; + } +} diff --git a/src/main/java/com/tikitaka/naechinso/global/config/security/jwt/JwtTokenProvider.java b/src/main/java/com/tikitaka/naechinso/global/config/security/jwt/JwtTokenProvider.java index 063c0c2..eeafe74 100644 --- a/src/main/java/com/tikitaka/naechinso/global/config/security/jwt/JwtTokenProvider.java +++ b/src/main/java/com/tikitaka/naechinso/global/config/security/jwt/JwtTokenProvider.java @@ -113,8 +113,8 @@ public Authentication getAuthentication(String accessToken) { .collect(Collectors.toList()); //Authentication 리턴 - UserDetails principal = new User(claims.getSubject(), "", authorities); - return new UsernamePasswordAuthenticationToken(principal, "", authorities); + UserDetails principal = new User(claims.getSubject(), null, authorities); + return new UsernamePasswordAuthenticationToken(principal, null, authorities); } diff --git a/src/main/java/com/tikitaka/naechinso/global/error/GlobalExceptionHandler.java b/src/main/java/com/tikitaka/naechinso/global/error/GlobalExceptionHandler.java index 180e790..97260a0 100644 --- a/src/main/java/com/tikitaka/naechinso/global/error/GlobalExceptionHandler.java +++ b/src/main/java/com/tikitaka/naechinso/global/error/GlobalExceptionHandler.java @@ -48,7 +48,7 @@ protected ResponseEntity handleMethodArgumentNotValidException(Me // @ExceptionHandler(MethodArgumentTypeMismatchException.class) // protected ResponseEntity handleMethodArgumentTypeMismatchException(MethodArgumentTypeMismatchException e) { // log.error("handleMethodArgumentTypeMismatchException", e); -// final ErrorResponse response = ErrorResponse.of((); +// final ErrorResponse response = ErrorResponse.of(e); // return new ResponseEntity<>(response, HttpStatus.BAD_REQUEST); // } From 2adc0474e5677d5dd9c214a11db904db67e1385d Mon Sep 17 00:00:00 2001 From: gengminy Date: Mon, 26 Sep 2022 02:04:21 +0900 Subject: [PATCH 03/72] =?UTF-8?q?:hammer:=20fix(user):=20=EB=A1=9C?= =?UTF-8?q?=EA=B7=B8=EC=9D=B8=20=EA=B8=B0=EB=8A=A5=20=EC=98=A4=EB=A5=98=20?= =?UTF-8?q?=EC=88=98=EC=A0=95=20#18?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../domain/member/MemberController.java | 12 ++++++--- .../domain/member/MemberService.java | 25 +++++++++++-------- .../sms/SmsCertificationServiceImpl.java | 12 ++++++--- .../config/security/LoginServiceImpl.java | 1 + .../config/security/SecurityConfig.java | 6 +++-- .../global/config/security/UserAccount.java | 2 +- .../security/jwt/JwtAuthenticationFilter.java | 6 ++++- .../config/security/jwt/JwtTokenProvider.java | 4 +-- 8 files changed, 44 insertions(+), 24 deletions(-) diff --git a/src/main/java/com/tikitaka/naechinso/domain/member/MemberController.java b/src/main/java/com/tikitaka/naechinso/domain/member/MemberController.java index 156a7ef..5ee97a3 100644 --- a/src/main/java/com/tikitaka/naechinso/domain/member/MemberController.java +++ b/src/main/java/com/tikitaka/naechinso/domain/member/MemberController.java @@ -5,6 +5,7 @@ import com.tikitaka.naechinso.domain.member.entity.Member; import com.tikitaka.naechinso.global.annotation.AuthMember; import com.tikitaka.naechinso.global.config.CommonApiResponse; +import com.tikitaka.naechinso.global.config.security.UserAccount; import com.tikitaka.naechinso.global.error.ErrorCode; import com.tikitaka.naechinso.global.error.exception.UnauthorizedException; import io.swagger.annotations.ApiOperation; @@ -15,6 +16,7 @@ import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; import org.springframework.security.core.annotation.AuthenticationPrincipal; +import org.springframework.security.core.userdetails.UserDetails; import org.springframework.stereotype.Controller; import org.springframework.web.bind.annotation.*; import springfox.documentation.annotations.ApiIgnore; @@ -32,15 +34,17 @@ public class MemberController { @GetMapping("/") @ApiOperation(value = "유저 자신의 정보를 가져온다 (AccessToken 필요)") - public CommonApiResponse getMyInformation(HttpServletRequest request, @ApiIgnore @AuthMember Member member) { - System.out.println("member = " + member);/// + public CommonApiResponse getMyInformation(HttpServletRequest request, @ApiIgnore @AuthMember UserAccount user) { + System.out.println("userDetails = " + user);/// - if (member == null) { + if (user == null) { throw new UnauthorizedException(ErrorCode.UNAUTHORIZED_USER); } - return CommonApiResponse.of(MemberCommonJoinResponseDto.of(member)); +// return CommonApiResponse.of(MemberCommonJoinResponseDto.of(userDetails)); + return CommonApiResponse.of(user); + } diff --git a/src/main/java/com/tikitaka/naechinso/domain/member/MemberService.java b/src/main/java/com/tikitaka/naechinso/domain/member/MemberService.java index aeb587a..c35fa47 100644 --- a/src/main/java/com/tikitaka/naechinso/domain/member/MemberService.java +++ b/src/main/java/com/tikitaka/naechinso/domain/member/MemberService.java @@ -5,6 +5,7 @@ import com.tikitaka.naechinso.domain.member.entity.Member; import com.tikitaka.naechinso.domain.member.entity.MemberDetail; import com.tikitaka.naechinso.global.common.response.TokenResponseDTO; +import com.tikitaka.naechinso.global.config.security.UserAccount; import com.tikitaka.naechinso.global.config.security.dto.JwtDTO; import com.tikitaka.naechinso.global.config.security.jwt.JwtTokenProvider; import com.tikitaka.naechinso.global.error.ErrorCode; @@ -13,9 +14,12 @@ import org.springframework.security.authentication.UsernamePasswordAuthenticationToken; import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder; import org.springframework.security.core.Authentication; +import org.springframework.security.core.authority.SimpleGrantedAuthority; +import org.springframework.security.core.context.SecurityContextHolder; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; +import java.util.List; import java.util.Optional; @Service @@ -46,24 +50,25 @@ public MemberCommonJoinResponseDto joinCommonMember(MemberCommonJoinRequestDto d public TokenResponseDTO login(String phone) { System.out.println("phone = " + phone); + Member checkMember = memberRepository.findByPhone(phone) + .orElseThrow(() -> new BadRequestException(ErrorCode.USER_NOT_FOUND)); UsernamePasswordAuthenticationToken authenticationToken - = new UsernamePasswordAuthenticationToken(phone, null); + = new UsernamePasswordAuthenticationToken(new UserAccount(checkMember), "", List.of(new SimpleGrantedAuthority("ROLE_USER"))); - // 2. 실제로 검증 (사용자 비밀번호 체크) 이 이루어지는 부분 - // authenticate 메서드가 실행이 될 때 - // LoginServiceImpl의 loadUserByUsername 메서드가 실행됨 - Authentication authentication - = authenticationManagerBuilder.getObject().authenticate(authenticationToken); +// // 2. 실제로 검증 (사용자 비밀번호 체크) 이 이루어지는 부분 +// // authenticate 메서드가 실행이 될 때 +// // LoginServiceImpl의 loadUserByUsername 메서드가 실행됨 +// Authentication authentication +// = authenticationManagerBuilder.getObject().authenticate(authenticationToken); - - - System.out.println("1 = " + 1); + SecurityContextHolder.getContext().setAuthentication(authenticationToken); TokenResponseDTO tokenResponseDTO = jwtTokenProvider.generateToken(new JwtDTO(phone)); - System.out.println("2 = " + 2); + //리프레시 토큰 저장 로직 아래에 + return tokenResponseDTO; } diff --git a/src/main/java/com/tikitaka/naechinso/domain/sms/SmsCertificationServiceImpl.java b/src/main/java/com/tikitaka/naechinso/domain/sms/SmsCertificationServiceImpl.java index 956327b..1ead487 100644 --- a/src/main/java/com/tikitaka/naechinso/domain/sms/SmsCertificationServiceImpl.java +++ b/src/main/java/com/tikitaka/naechinso/domain/sms/SmsCertificationServiceImpl.java @@ -110,8 +110,6 @@ public TokenResponseDTO verifyCode(SmsCertificationRequestDTO smsCertificationRe //redis 인증 필터 성공하면 try { - redisService.deleteValues(key); - //가입 안된 회원일 경우 null 리턴 Optional checkMember = memberRepository.findByPhone(phoneNumber); if (checkMember.isEmpty()) { @@ -119,8 +117,14 @@ public TokenResponseDTO verifyCode(SmsCertificationRequestDTO smsCertificationRe } //이미 가입한 회원이면 - //인증한 휴대폰 번호로 로그인 후 토큰 생성 및 반환 - return memberService.login(phoneNumber); + //인증한 휴대폰 번호로 로그인 후 토큰 생성 + TokenResponseDTO tokenResponseDTO = memberService.login(phoneNumber); + + //redis 에서 번호 제거 + redisService.deleteValues(key); + + //토큰 반환 + return tokenResponseDTO; } catch (Exception e) { e.printStackTrace(); throw new InternalServerException("jwt 토큰 생성 에러"); diff --git a/src/main/java/com/tikitaka/naechinso/global/config/security/LoginServiceImpl.java b/src/main/java/com/tikitaka/naechinso/global/config/security/LoginServiceImpl.java index c4019f5..2c5cbdd 100644 --- a/src/main/java/com/tikitaka/naechinso/global/config/security/LoginServiceImpl.java +++ b/src/main/java/com/tikitaka/naechinso/global/config/security/LoginServiceImpl.java @@ -29,6 +29,7 @@ public UserDetails loadUserByUsername(String phone) throws UsernameNotFoundExcep .orElseThrow(() -> { throw new UsernameNotFoundException(phone + "-> DB에 없는 유저"); }); return new UserAccount(member); +// return new User(member.getPhone(), "", Collections.singletonList(new SimpleGrantedAuthority("ROLE_USER"))); } // // //DB에 존재하는 유저일 경우 UserDetails로 만들어서 반환 diff --git a/src/main/java/com/tikitaka/naechinso/global/config/security/SecurityConfig.java b/src/main/java/com/tikitaka/naechinso/global/config/security/SecurityConfig.java index aed6b05..a6a5539 100644 --- a/src/main/java/com/tikitaka/naechinso/global/config/security/SecurityConfig.java +++ b/src/main/java/com/tikitaka/naechinso/global/config/security/SecurityConfig.java @@ -55,8 +55,10 @@ public SecurityFilterChain filterChain(HttpSecurity http) throws Exception { .requestMatchers(CorsUtils::isPreFlightRequest).permitAll() .antMatchers(SwaggerPatterns).permitAll() .antMatchers("/admin/**").hasAuthority("ROLE_ADMIN") - .antMatchers("/user/**").authenticated() - .anyRequest().permitAll() + .antMatchers("/member/login").permitAll() + .antMatchers("/member/join").permitAll() + .antMatchers("/sms/**").permitAll() + .anyRequest().authenticated() .and() .headers().frameOptions().disable(); diff --git a/src/main/java/com/tikitaka/naechinso/global/config/security/UserAccount.java b/src/main/java/com/tikitaka/naechinso/global/config/security/UserAccount.java index 6fdac7c..2ef8468 100644 --- a/src/main/java/com/tikitaka/naechinso/global/config/security/UserAccount.java +++ b/src/main/java/com/tikitaka/naechinso/global/config/security/UserAccount.java @@ -14,7 +14,7 @@ public class UserAccount extends User { private Member member; public UserAccount(Member member) { - super(member.getPhone(), null, List.of(new SimpleGrantedAuthority("ROLE_USER"))); + super(member.getPhone(), "", List.of(new SimpleGrantedAuthority("ROLE_USER"))); this.member = member; } } diff --git a/src/main/java/com/tikitaka/naechinso/global/config/security/jwt/JwtAuthenticationFilter.java b/src/main/java/com/tikitaka/naechinso/global/config/security/jwt/JwtAuthenticationFilter.java index a9a357f..9237679 100644 --- a/src/main/java/com/tikitaka/naechinso/global/config/security/jwt/JwtAuthenticationFilter.java +++ b/src/main/java/com/tikitaka/naechinso/global/config/security/jwt/JwtAuthenticationFilter.java @@ -3,8 +3,10 @@ import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; import org.apache.commons.lang3.StringUtils; +import org.springframework.security.authentication.UsernamePasswordAuthenticationToken; import org.springframework.security.core.Authentication; 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; @@ -35,7 +37,9 @@ protected void doFilterInternal(HttpServletRequest request, HttpServletResponse if (StringUtils.isNotBlank(jwt) && jwtTokenService.validateToken(jwt)) { Authentication authentication = jwtTokenService.getAuthentication(jwt); //authentication 획득 -// authentication.setDetails(new WebAuthenticationDetailsSource().buildDetails(request)); //기본적으로 제공한 details 세팅 + + ((UsernamePasswordAuthenticationToken) authentication).setDetails( + new WebAuthenticationDetailsSource().buildDetails(request)); //기본적으로 제공한 details 세팅 //Security 세션에서 계속 사용하기 위해 SecurityContext에 Authentication 등록 SecurityContextHolder.getContext().setAuthentication(authentication); diff --git a/src/main/java/com/tikitaka/naechinso/global/config/security/jwt/JwtTokenProvider.java b/src/main/java/com/tikitaka/naechinso/global/config/security/jwt/JwtTokenProvider.java index eeafe74..063c0c2 100644 --- a/src/main/java/com/tikitaka/naechinso/global/config/security/jwt/JwtTokenProvider.java +++ b/src/main/java/com/tikitaka/naechinso/global/config/security/jwt/JwtTokenProvider.java @@ -113,8 +113,8 @@ public Authentication getAuthentication(String accessToken) { .collect(Collectors.toList()); //Authentication 리턴 - UserDetails principal = new User(claims.getSubject(), null, authorities); - return new UsernamePasswordAuthenticationToken(principal, null, authorities); + UserDetails principal = new User(claims.getSubject(), "", authorities); + return new UsernamePasswordAuthenticationToken(principal, "", authorities); } From 1ad39403f434c8b9c79556eff1fc39be6b819c0f Mon Sep 17 00:00:00 2001 From: gengminy Date: Mon, 26 Sep 2022 13:44:28 +0900 Subject: [PATCH 04/72] =?UTF-8?q?:hammer:=20fix(user):=20=EB=A1=9C?= =?UTF-8?q?=EA=B7=B8=EC=9D=B8=20=EC=84=9C=EB=B9=84=EC=8A=A4=20=EC=88=98?= =?UTF-8?q?=EC=A0=95=20#18?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../domain/member/MemberController.java | 22 ++++++++++--------- .../domain/member/MemberService.java | 6 ++--- .../global/annotation/AuthMember.java | 2 +- .../config/security/LoginServiceImpl.java | 8 +------ ...Account.java => MemberAccountAdapter.java} | 6 ++--- .../security/jwt/JwtAuthenticationFilter.java | 4 ++-- 6 files changed, 20 insertions(+), 28 deletions(-) rename src/main/java/com/tikitaka/naechinso/global/config/security/{UserAccount.java => MemberAccountAdapter.java} (73%) diff --git a/src/main/java/com/tikitaka/naechinso/domain/member/MemberController.java b/src/main/java/com/tikitaka/naechinso/domain/member/MemberController.java index 5ee97a3..f7d5582 100644 --- a/src/main/java/com/tikitaka/naechinso/domain/member/MemberController.java +++ b/src/main/java/com/tikitaka/naechinso/domain/member/MemberController.java @@ -5,19 +5,17 @@ import com.tikitaka.naechinso.domain.member.entity.Member; import com.tikitaka.naechinso.global.annotation.AuthMember; import com.tikitaka.naechinso.global.config.CommonApiResponse; -import com.tikitaka.naechinso.global.config.security.UserAccount; +import com.tikitaka.naechinso.global.config.security.LoginServiceImpl; +import com.tikitaka.naechinso.global.config.security.MemberAccountAdapter; import com.tikitaka.naechinso.global.error.ErrorCode; import com.tikitaka.naechinso.global.error.exception.UnauthorizedException; import io.swagger.annotations.ApiOperation; -import io.swagger.annotations.ApiParam; -import io.swagger.annotations.Authorization; -import io.swagger.v3.oas.annotations.Hidden; -import io.swagger.v3.oas.annotations.Parameter; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; +import org.springframework.security.core.Authentication; import org.springframework.security.core.annotation.AuthenticationPrincipal; +import org.springframework.security.core.context.SecurityContextHolder; import org.springframework.security.core.userdetails.UserDetails; -import org.springframework.stereotype.Controller; import org.springframework.web.bind.annotation.*; import springfox.documentation.annotations.ApiIgnore; @@ -34,16 +32,20 @@ public class MemberController { @GetMapping("/") @ApiOperation(value = "유저 자신의 정보를 가져온다 (AccessToken 필요)") - public CommonApiResponse getMyInformation(HttpServletRequest request, @ApiIgnore @AuthMember UserAccount user) { - System.out.println("userDetails = " + user);/// + public CommonApiResponse getMyInformation(HttpServletRequest request, @ApiIgnore @AuthenticationPrincipal MemberAccountAdapter accountAdapter) { + System.out.println("SecurityContextHolder.getContext() = " + SecurityContextHolder.getContext()); + System.out.println("SecurityContextHolder.getContext().getAuthentication() = " + SecurityContextHolder.getContext().getAuthentication()); - if (user == null) { + + Member member = accountAdapter.getMember(); + + if (member == null) { throw new UnauthorizedException(ErrorCode.UNAUTHORIZED_USER); } // return CommonApiResponse.of(MemberCommonJoinResponseDto.of(userDetails)); - return CommonApiResponse.of(user); + return CommonApiResponse.of(member); } diff --git a/src/main/java/com/tikitaka/naechinso/domain/member/MemberService.java b/src/main/java/com/tikitaka/naechinso/domain/member/MemberService.java index c35fa47..ec5f5c8 100644 --- a/src/main/java/com/tikitaka/naechinso/domain/member/MemberService.java +++ b/src/main/java/com/tikitaka/naechinso/domain/member/MemberService.java @@ -3,9 +3,8 @@ import com.tikitaka.naechinso.domain.member.dto.MemberCommonJoinRequestDto; import com.tikitaka.naechinso.domain.member.dto.MemberCommonJoinResponseDto; import com.tikitaka.naechinso.domain.member.entity.Member; -import com.tikitaka.naechinso.domain.member.entity.MemberDetail; import com.tikitaka.naechinso.global.common.response.TokenResponseDTO; -import com.tikitaka.naechinso.global.config.security.UserAccount; +import com.tikitaka.naechinso.global.config.security.MemberAccountAdapter; import com.tikitaka.naechinso.global.config.security.dto.JwtDTO; import com.tikitaka.naechinso.global.config.security.jwt.JwtTokenProvider; import com.tikitaka.naechinso.global.error.ErrorCode; @@ -13,7 +12,6 @@ import lombok.RequiredArgsConstructor; import org.springframework.security.authentication.UsernamePasswordAuthenticationToken; import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder; -import org.springframework.security.core.Authentication; import org.springframework.security.core.authority.SimpleGrantedAuthority; import org.springframework.security.core.context.SecurityContextHolder; import org.springframework.stereotype.Service; @@ -54,7 +52,7 @@ public TokenResponseDTO login(String phone) { .orElseThrow(() -> new BadRequestException(ErrorCode.USER_NOT_FOUND)); UsernamePasswordAuthenticationToken authenticationToken - = new UsernamePasswordAuthenticationToken(new UserAccount(checkMember), "", List.of(new SimpleGrantedAuthority("ROLE_USER"))); + = new UsernamePasswordAuthenticationToken(new MemberAccountAdapter(checkMember), "", List.of(new SimpleGrantedAuthority("ROLE_USER"))); // // 2. 실제로 검증 (사용자 비밀번호 체크) 이 이루어지는 부분 // // authenticate 메서드가 실행이 될 때 diff --git a/src/main/java/com/tikitaka/naechinso/global/annotation/AuthMember.java b/src/main/java/com/tikitaka/naechinso/global/annotation/AuthMember.java index f331b4a..9ffe5f6 100644 --- a/src/main/java/com/tikitaka/naechinso/global/annotation/AuthMember.java +++ b/src/main/java/com/tikitaka/naechinso/global/annotation/AuthMember.java @@ -9,6 +9,6 @@ @Target(ElementType.PARAMETER) @Retention(RetentionPolicy.RUNTIME) -@AuthenticationPrincipal(expression = "#this == 'anonymousUser ? null : member'") +@AuthenticationPrincipal(expression = "member") public @interface AuthMember { } diff --git a/src/main/java/com/tikitaka/naechinso/global/config/security/LoginServiceImpl.java b/src/main/java/com/tikitaka/naechinso/global/config/security/LoginServiceImpl.java index 2c5cbdd..6d9a06a 100644 --- a/src/main/java/com/tikitaka/naechinso/global/config/security/LoginServiceImpl.java +++ b/src/main/java/com/tikitaka/naechinso/global/config/security/LoginServiceImpl.java @@ -4,17 +4,12 @@ import com.tikitaka.naechinso.domain.member.MemberRepository; import com.tikitaka.naechinso.domain.member.entity.Member; import lombok.RequiredArgsConstructor; -import org.springframework.security.core.GrantedAuthority; -import org.springframework.security.core.authority.SimpleGrantedAuthority; -import org.springframework.security.core.userdetails.User; import org.springframework.security.core.userdetails.UserDetails; import org.springframework.security.core.userdetails.UserDetailsService; import org.springframework.security.core.userdetails.UsernameNotFoundException; import org.springframework.stereotype.Service; import javax.transaction.Transactional; -import java.util.Collections; -import java.util.Optional; @RequiredArgsConstructor @Service @@ -23,12 +18,11 @@ public class LoginServiceImpl implements UserDetailsService { private final MemberRepository memberRepository; @Override - @Transactional public UserDetails loadUserByUsername(String phone) throws UsernameNotFoundException { Member member = memberRepository.findByPhone(phone) .orElseThrow(() -> { throw new UsernameNotFoundException(phone + "-> DB에 없는 유저"); }); - return new UserAccount(member); + return new MemberAccountAdapter(member); // return new User(member.getPhone(), "", Collections.singletonList(new SimpleGrantedAuthority("ROLE_USER"))); } // diff --git a/src/main/java/com/tikitaka/naechinso/global/config/security/UserAccount.java b/src/main/java/com/tikitaka/naechinso/global/config/security/MemberAccountAdapter.java similarity index 73% rename from src/main/java/com/tikitaka/naechinso/global/config/security/UserAccount.java rename to src/main/java/com/tikitaka/naechinso/global/config/security/MemberAccountAdapter.java index 2ef8468..9e5f4a2 100644 --- a/src/main/java/com/tikitaka/naechinso/global/config/security/UserAccount.java +++ b/src/main/java/com/tikitaka/naechinso/global/config/security/MemberAccountAdapter.java @@ -2,18 +2,16 @@ import com.tikitaka.naechinso.domain.member.entity.Member; import lombok.Getter; -import org.springframework.security.core.GrantedAuthority; import org.springframework.security.core.authority.SimpleGrantedAuthority; import org.springframework.security.core.userdetails.User; -import java.util.Collection; import java.util.List; @Getter -public class UserAccount extends User { +public class MemberAccountAdapter extends User { private Member member; - public UserAccount(Member member) { + public MemberAccountAdapter(Member member) { super(member.getPhone(), "", List.of(new SimpleGrantedAuthority("ROLE_USER"))); this.member = member; } diff --git a/src/main/java/com/tikitaka/naechinso/global/config/security/jwt/JwtAuthenticationFilter.java b/src/main/java/com/tikitaka/naechinso/global/config/security/jwt/JwtAuthenticationFilter.java index 9237679..d9a1b55 100644 --- a/src/main/java/com/tikitaka/naechinso/global/config/security/jwt/JwtAuthenticationFilter.java +++ b/src/main/java/com/tikitaka/naechinso/global/config/security/jwt/JwtAuthenticationFilter.java @@ -38,8 +38,8 @@ protected void doFilterInternal(HttpServletRequest request, HttpServletResponse if (StringUtils.isNotBlank(jwt) && jwtTokenService.validateToken(jwt)) { Authentication authentication = jwtTokenService.getAuthentication(jwt); //authentication 획득 - ((UsernamePasswordAuthenticationToken) authentication).setDetails( - new WebAuthenticationDetailsSource().buildDetails(request)); //기본적으로 제공한 details 세팅 +// ((UsernamePasswordAuthenticationToken) authentication).setDetails( +// new WebAuthenticationDetailsSource().buildDetails(request)); //기본적으로 제공한 details 세팅 //Security 세션에서 계속 사용하기 위해 SecurityContext에 Authentication 등록 SecurityContextHolder.getContext().setAuthentication(authentication); From 9cbad7351a375aac6f7abd31fa1e15692b7ce294 Mon Sep 17 00:00:00 2001 From: gengminy Date: Mon, 26 Sep 2022 22:46:36 +0900 Subject: [PATCH 05/72] =?UTF-8?q?:rocket:=20feat(user):=20JWT=20=ED=9A=8C?= =?UTF-8?q?=EC=9B=90=EA=B0=80=EC=9E=85=20=EB=B0=8F=20=EB=A1=9C=EA=B7=B8?= =?UTF-8?q?=EC=9D=B8=20=EC=B5=9C=EC=86=8C=20=EA=B8=B0=EB=8A=A5=20#18?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../domain/member/MemberController.java | 21 +------- .../domain/member/MemberService.java | 12 +---- .../global/annotation/AuthMember.java | 10 +++- ...AccountAdapter.java => MemberAdapter.java} | 11 +++- .../config/security/SecurityConfig.java | 2 +- ...ceImpl.java => UserDetailServiceImpl.java} | 6 +-- .../jwt/JwtAuthenticationEntryPoint.java | 37 ++++++++++++- .../security/jwt/JwtAuthenticationFilter.java | 54 +++++++++++-------- .../config/security/jwt/JwtTokenProvider.java | 49 +++++++++++------ .../global/config/swagger/SwaggerConfig.java | 13 +++-- .../naechinso/global/error/ErrorCode.java | 12 +++-- .../naechinso/global/error/ErrorResponse.java | 12 +++++ .../global/error/GlobalExceptionHandler.java | 1 + 13 files changed, 151 insertions(+), 89 deletions(-) rename src/main/java/com/tikitaka/naechinso/global/config/security/{MemberAccountAdapter.java => MemberAdapter.java} (62%) rename src/main/java/com/tikitaka/naechinso/global/config/security/{LoginServiceImpl.java => UserDetailServiceImpl.java} (88%) diff --git a/src/main/java/com/tikitaka/naechinso/domain/member/MemberController.java b/src/main/java/com/tikitaka/naechinso/domain/member/MemberController.java index f7d5582..e27906e 100644 --- a/src/main/java/com/tikitaka/naechinso/domain/member/MemberController.java +++ b/src/main/java/com/tikitaka/naechinso/domain/member/MemberController.java @@ -5,19 +5,12 @@ import com.tikitaka.naechinso.domain.member.entity.Member; import com.tikitaka.naechinso.global.annotation.AuthMember; import com.tikitaka.naechinso.global.config.CommonApiResponse; -import com.tikitaka.naechinso.global.config.security.LoginServiceImpl; -import com.tikitaka.naechinso.global.config.security.MemberAccountAdapter; import com.tikitaka.naechinso.global.error.ErrorCode; import com.tikitaka.naechinso.global.error.exception.UnauthorizedException; import io.swagger.annotations.ApiOperation; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; -import org.springframework.security.core.Authentication; -import org.springframework.security.core.annotation.AuthenticationPrincipal; -import org.springframework.security.core.context.SecurityContextHolder; -import org.springframework.security.core.userdetails.UserDetails; import org.springframework.web.bind.annotation.*; -import springfox.documentation.annotations.ApiIgnore; import javax.servlet.http.HttpServletRequest; import javax.validation.Valid; @@ -32,21 +25,11 @@ public class MemberController { @GetMapping("/") @ApiOperation(value = "유저 자신의 정보를 가져온다 (AccessToken 필요)") - public CommonApiResponse getMyInformation(HttpServletRequest request, @ApiIgnore @AuthenticationPrincipal MemberAccountAdapter accountAdapter) { - - System.out.println("SecurityContextHolder.getContext() = " + SecurityContextHolder.getContext()); - System.out.println("SecurityContextHolder.getContext().getAuthentication() = " + SecurityContextHolder.getContext().getAuthentication()); - - - Member member = accountAdapter.getMember(); - + public CommonApiResponse getMyInformation(HttpServletRequest request, @AuthMember Member member) { if (member == null) { throw new UnauthorizedException(ErrorCode.UNAUTHORIZED_USER); } - -// return CommonApiResponse.of(MemberCommonJoinResponseDto.of(userDetails)); - return CommonApiResponse.of(member); - + return CommonApiResponse.of(MemberCommonJoinResponseDto.of(member)); } diff --git a/src/main/java/com/tikitaka/naechinso/domain/member/MemberService.java b/src/main/java/com/tikitaka/naechinso/domain/member/MemberService.java index ec5f5c8..cbe743f 100644 --- a/src/main/java/com/tikitaka/naechinso/domain/member/MemberService.java +++ b/src/main/java/com/tikitaka/naechinso/domain/member/MemberService.java @@ -4,7 +4,7 @@ import com.tikitaka.naechinso.domain.member.dto.MemberCommonJoinResponseDto; import com.tikitaka.naechinso.domain.member.entity.Member; import com.tikitaka.naechinso.global.common.response.TokenResponseDTO; -import com.tikitaka.naechinso.global.config.security.MemberAccountAdapter; +import com.tikitaka.naechinso.global.config.security.MemberAdapter; import com.tikitaka.naechinso.global.config.security.dto.JwtDTO; import com.tikitaka.naechinso.global.config.security.jwt.JwtTokenProvider; import com.tikitaka.naechinso.global.error.ErrorCode; @@ -52,13 +52,7 @@ public TokenResponseDTO login(String phone) { .orElseThrow(() -> new BadRequestException(ErrorCode.USER_NOT_FOUND)); UsernamePasswordAuthenticationToken authenticationToken - = new UsernamePasswordAuthenticationToken(new MemberAccountAdapter(checkMember), "", List.of(new SimpleGrantedAuthority("ROLE_USER"))); - -// // 2. 실제로 검증 (사용자 비밀번호 체크) 이 이루어지는 부분 -// // authenticate 메서드가 실행이 될 때 -// // LoginServiceImpl의 loadUserByUsername 메서드가 실행됨 -// Authentication authentication -// = authenticationManagerBuilder.getObject().authenticate(authenticationToken); + = new UsernamePasswordAuthenticationToken(new MemberAdapter(checkMember), "", List.of(new SimpleGrantedAuthority("ROLE_USER"))); SecurityContextHolder.getContext().setAuthentication(authenticationToken); @@ -66,8 +60,6 @@ public TokenResponseDTO login(String phone) { = jwtTokenProvider.generateToken(new JwtDTO(phone)); //리프레시 토큰 저장 로직 아래에 - - return tokenResponseDTO; } diff --git a/src/main/java/com/tikitaka/naechinso/global/annotation/AuthMember.java b/src/main/java/com/tikitaka/naechinso/global/annotation/AuthMember.java index 9ffe5f6..de5cec8 100644 --- a/src/main/java/com/tikitaka/naechinso/global/annotation/AuthMember.java +++ b/src/main/java/com/tikitaka/naechinso/global/annotation/AuthMember.java @@ -7,8 +7,16 @@ import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target; +/** + * request 의 Authorization 헤더를 가지고 + * JwtAuthenticationFilter 를 통과하면서 + * SecurityContextHolder 에 로그인 된 유저의 + * UserDetails 의 커스텀 구현체 MemberAdapter 를 가져온 후 + * member property 를 추출하는 어노테이션 + * @author gengimny 220926 + * */ @Target(ElementType.PARAMETER) @Retention(RetentionPolicy.RUNTIME) -@AuthenticationPrincipal(expression = "member") +@AuthenticationPrincipal(expression = "#this == 'anonymousUser' ? null : member") public @interface AuthMember { } diff --git a/src/main/java/com/tikitaka/naechinso/global/config/security/MemberAccountAdapter.java b/src/main/java/com/tikitaka/naechinso/global/config/security/MemberAdapter.java similarity index 62% rename from src/main/java/com/tikitaka/naechinso/global/config/security/MemberAccountAdapter.java rename to src/main/java/com/tikitaka/naechinso/global/config/security/MemberAdapter.java index 9e5f4a2..35b6514 100644 --- a/src/main/java/com/tikitaka/naechinso/global/config/security/MemberAccountAdapter.java +++ b/src/main/java/com/tikitaka/naechinso/global/config/security/MemberAdapter.java @@ -7,12 +7,19 @@ import java.util.List; +/** + * UserDetails 를 구현한 어댑터 + * Spring Security Authentication 사용 시 + * Member Entity 를 가져오기 편하게 하기 위해 구현 + * @author gengminy 220926 + * */ @Getter -public class MemberAccountAdapter extends User { +public class MemberAdapter extends User { private Member member; - public MemberAccountAdapter(Member member) { + public MemberAdapter(Member member) { super(member.getPhone(), "", List.of(new SimpleGrantedAuthority("ROLE_USER"))); this.member = member; } + } diff --git a/src/main/java/com/tikitaka/naechinso/global/config/security/SecurityConfig.java b/src/main/java/com/tikitaka/naechinso/global/config/security/SecurityConfig.java index a6a5539..5a454d6 100644 --- a/src/main/java/com/tikitaka/naechinso/global/config/security/SecurityConfig.java +++ b/src/main/java/com/tikitaka/naechinso/global/config/security/SecurityConfig.java @@ -26,7 +26,7 @@ public class SecurityConfig { private static final String[] SwaggerPatterns = { "/swagger-resources/**", - "/swagger-ui.html", + "/swagger-ui/**", "/v2/api-docs", "/webjars/**" }; diff --git a/src/main/java/com/tikitaka/naechinso/global/config/security/LoginServiceImpl.java b/src/main/java/com/tikitaka/naechinso/global/config/security/UserDetailServiceImpl.java similarity index 88% rename from src/main/java/com/tikitaka/naechinso/global/config/security/LoginServiceImpl.java rename to src/main/java/com/tikitaka/naechinso/global/config/security/UserDetailServiceImpl.java index 6d9a06a..6b2e5d2 100644 --- a/src/main/java/com/tikitaka/naechinso/global/config/security/LoginServiceImpl.java +++ b/src/main/java/com/tikitaka/naechinso/global/config/security/UserDetailServiceImpl.java @@ -9,11 +9,9 @@ import org.springframework.security.core.userdetails.UsernameNotFoundException; import org.springframework.stereotype.Service; -import javax.transaction.Transactional; - @RequiredArgsConstructor @Service -public class LoginServiceImpl implements UserDetailsService { +public class UserDetailServiceImpl implements UserDetailsService { private final MemberRepository memberRepository; @@ -22,7 +20,7 @@ public UserDetails loadUserByUsername(String phone) throws UsernameNotFoundExcep Member member = memberRepository.findByPhone(phone) .orElseThrow(() -> { throw new UsernameNotFoundException(phone + "-> DB에 없는 유저"); }); - return new MemberAccountAdapter(member); + return new MemberAdapter(member); // return new User(member.getPhone(), "", Collections.singletonList(new SimpleGrantedAuthority("ROLE_USER"))); } // diff --git a/src/main/java/com/tikitaka/naechinso/global/config/security/jwt/JwtAuthenticationEntryPoint.java b/src/main/java/com/tikitaka/naechinso/global/config/security/jwt/JwtAuthenticationEntryPoint.java index 344050d..8859703 100644 --- a/src/main/java/com/tikitaka/naechinso/global/config/security/jwt/JwtAuthenticationEntryPoint.java +++ b/src/main/java/com/tikitaka/naechinso/global/config/security/jwt/JwtAuthenticationEntryPoint.java @@ -1,8 +1,10 @@ package com.tikitaka.naechinso.global.config.security.jwt; import com.tikitaka.naechinso.global.error.ErrorCode; +import com.tikitaka.naechinso.global.error.ErrorResponse; import com.tikitaka.naechinso.global.error.exception.UnauthorizedException; import lombok.extern.slf4j.Slf4j; +import org.json.JSONObject; import org.springframework.security.core.AuthenticationException; import org.springframework.security.web.AuthenticationEntryPoint; import org.springframework.stereotype.Component; @@ -20,7 +22,38 @@ public void commence( HttpServletResponse response, AuthenticationException e ) throws IOException { - //유저 정보가 없을 경우 401 Unauthorized Error - throw new UnauthorizedException(ErrorCode.INVALID_AUTH_TOKEN); + String exception = (String)request.getAttribute("exception"); + + if(exception == null || exception.equals(ErrorCode.NO_TOKEN.getCode())) { + setResponse(response, ErrorCode.NO_TOKEN); + } + //잘못된 타입의 토큰인 경우 + else if(exception.equals(ErrorCode.INVALID_AUTH_TOKEN.getCode())) { + setResponse(response, ErrorCode.INVALID_AUTH_TOKEN); + } + //잘못된 서명 + else if(exception.equals(ErrorCode.INVALID_SIGNATURE.getCode())) { + setResponse(response, ErrorCode.INVALID_SIGNATURE); + } + //토큰 만료된 경우 + else if(exception.equals(ErrorCode.EXPIRED_TOKEN.getCode())) { + setResponse(response, ErrorCode.EXPIRED_TOKEN); + } + //지원되지 않는 토큰인 경우 + else if(exception.equals(ErrorCode.UNSUPPORTED_TOKEN.getCode())) { + setResponse(response, ErrorCode.UNSUPPORTED_TOKEN); + } + else { + setResponse(response, ErrorCode.FORBIDDEN_USER); + } + } + + /** + * 스프링 시큐티리 예외 커스텀을 위한 함수 + */ + private void setResponse(HttpServletResponse response, ErrorCode errorCode) throws IOException { + response.setContentType("application/json;charset=UTF-8"); + response.setStatus(HttpServletResponse.SC_UNAUTHORIZED); + response.getWriter().print(ErrorResponse.jsonOf(errorCode)); } } diff --git a/src/main/java/com/tikitaka/naechinso/global/config/security/jwt/JwtAuthenticationFilter.java b/src/main/java/com/tikitaka/naechinso/global/config/security/jwt/JwtAuthenticationFilter.java index d9a1b55..9a10146 100644 --- a/src/main/java/com/tikitaka/naechinso/global/config/security/jwt/JwtAuthenticationFilter.java +++ b/src/main/java/com/tikitaka/naechinso/global/config/security/jwt/JwtAuthenticationFilter.java @@ -1,5 +1,6 @@ package com.tikitaka.naechinso.global.config.security.jwt; +import com.tikitaka.naechinso.global.error.ErrorCode; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; import org.apache.commons.lang3.StringUtils; @@ -25,35 +26,46 @@ public class JwtAuthenticationFilter extends OncePerRequestFilter { @Override protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException { - try { - String jwt = resolveToken(request); //request에서 jwt 토큰을 꺼낸다. - if (jwt == null) { - filterChain.doFilter(request, response); - return; - } + //Spring Security 에 저장되어 있지 않으면 헤더에서 jwt 토큰을 가지고옴 + if (SecurityContextHolder.getContext().getAuthentication() == null) { + try { + String jwt = resolveToken(request); //request에서 jwt 토큰을 꺼낸다. - System.out.println("jwt = " + jwt); //test + if (jwt == null) { + log.error("jwt 값을 가져올 수 없습니다"); + request.setAttribute("exception", ErrorCode.NO_TOKEN.getCode()); + filterChain.doFilter(request, response); + return; + } - if (StringUtils.isNotBlank(jwt) && jwtTokenService.validateToken(jwt)) { - Authentication authentication = jwtTokenService.getAuthentication(jwt); //authentication 획득 +// // 만료 10분 전 리프레시 토큰으로 reissue +// if (canRefresh(claims, 6000 * 10)) { +// String refreshedToken = jwt.refreshToken(authorizationToken); +// response.setHeader(headerkey, refreshedToken); +// } -// ((UsernamePasswordAuthenticationToken) authentication).setDetails( -// new WebAuthenticationDetailsSource().buildDetails(request)); //기본적으로 제공한 details 세팅 + if (StringUtils.isNotBlank(jwt) && jwtTokenService.validateToken(jwt)) { + Authentication authentication = jwtTokenService.getAuthentication(jwt); //authentication 획득 - //Security 세션에서 계속 사용하기 위해 SecurityContext에 Authentication 등록 - SecurityContextHolder.getContext().setAuthentication(authentication); - } else { - if (StringUtils.isBlank(jwt)) { - request.setAttribute("unauthorization", "401 인증키 없음."); - } + //Security 세션에서 계속 사용하기 위해 SecurityContext에 Authentication 등록 + SecurityContextHolder.getContext().setAuthentication(authentication); + } else { + if (StringUtils.isBlank(jwt)) { + request.setAttribute("exception", ErrorCode.NO_TOKEN.getCode()); + } - if (jwtTokenService.validateToken(jwt)) { - request.setAttribute("unauthorization", "401-001 인증키 만료."); + if (!jwtTokenService.validateToken(jwt, request)){ + + } } + } catch (Exception ex) { + logger.error("Security Context에 해당 토큰을 등록할 수 없습니다", ex); } - } catch (Exception ex) { - logger.error("Security Context에 해당 토큰을 등록할 수 없습니다", ex); + } + else { + log.debug("SecurityContextHolder not populated with security token, as it already contained: '{}'", + SecurityContextHolder.getContext().getAuthentication()); } filterChain.doFilter(request, response); diff --git a/src/main/java/com/tikitaka/naechinso/global/config/security/jwt/JwtTokenProvider.java b/src/main/java/com/tikitaka/naechinso/global/config/security/jwt/JwtTokenProvider.java index 063c0c2..47e7d3d 100644 --- a/src/main/java/com/tikitaka/naechinso/global/config/security/jwt/JwtTokenProvider.java +++ b/src/main/java/com/tikitaka/naechinso/global/config/security/jwt/JwtTokenProvider.java @@ -1,6 +1,7 @@ package com.tikitaka.naechinso.global.config.security.jwt; import com.tikitaka.naechinso.global.common.response.TokenResponseDTO; +import com.tikitaka.naechinso.global.config.security.UserDetailServiceImpl; import com.tikitaka.naechinso.global.config.security.dto.JwtDTO; import com.tikitaka.naechinso.global.error.ErrorCode; import com.tikitaka.naechinso.global.error.exception.BadRequestException; @@ -12,25 +13,20 @@ import org.springframework.beans.factory.annotation.Value; import org.springframework.security.authentication.UsernamePasswordAuthenticationToken; import org.springframework.security.core.Authentication; -import org.springframework.security.core.GrantedAuthority; -import org.springframework.security.core.authority.SimpleGrantedAuthority; -import org.springframework.security.core.userdetails.User; import org.springframework.security.core.userdetails.UserDetails; import org.springframework.stereotype.Component; import org.springframework.web.client.HttpServerErrorException; +import javax.servlet.http.HttpServletRequest; import java.time.Duration; -import java.util.Arrays; -import java.util.Base64; -import java.util.Collection; -import java.util.Date; -import java.util.stream.Collectors; +import java.util.*; @Slf4j @Component @RequiredArgsConstructor public class JwtTokenProvider { private final RedisService redisService; + private final UserDetailServiceImpl loginService; /** 토큰 비밀 키 */ @Value("${jwt.secret-key}") private String JWT_SECRET; @@ -106,15 +102,8 @@ public Authentication getAuthentication(String accessToken) { throw new UnauthorizedException(ErrorCode.INVALID_AUTH_TOKEN); } - //권한 정보 가져오기 - Collection authorities = - Arrays.stream(claims.get(AUTHORITIES_KEY).toString().split(",")) - .map(SimpleGrantedAuthority::new) - .collect(Collectors.toList()); - - //Authentication 리턴 - UserDetails principal = new User(claims.getSubject(), "", authorities); - return new UsernamePasswordAuthenticationToken(principal, "", authorities); + UserDetails principal = loginService.loadUserByUsername(claims.getSubject()); + return new UsernamePasswordAuthenticationToken(principal, "", principal.getAuthorities()); } @@ -145,6 +134,32 @@ public boolean validateToken(String token) { return false; } + /** + * JWT 유효성 검사 오버로딩, 에러 커스텀을 위한 함수 + * @param token 검사하려는 JWT 토큰 + * @returns boolean + * */ + public boolean validateToken(String token, HttpServletRequest request) { + final String encodedKey = Base64.getEncoder().encodeToString(JWT_SECRET.getBytes()); + try { + Jwts.parser().setSigningKey(encodedKey).parseClaimsJws(token); + return true; + } catch (SignatureException | MalformedJwtException ex) { + log.error("잘못된 JWT 서명입니다"); + request.setAttribute("exception", ErrorCode.INVALID_SIGNATURE.getCode()); + } catch (ExpiredJwtException ex) { + log.error("만료된 JWT 토큰입니다"); + request.setAttribute("exception", ErrorCode.EXPIRED_TOKEN.getCode()); + } catch (UnsupportedJwtException ex) { + log.error("지원하지 않는 JWT 토큰입니다"); + request.setAttribute("exception", ErrorCode.UNSUPPORTED_TOKEN.getCode()); + } catch (IllegalArgumentException ex) { + log.error("JWT 토큰이 비어있습니다"); + request.setAttribute("exception", ErrorCode.NO_TOKEN.getCode()); + } + return false; + } + /** Redis Memory 의 RefreshToken 과 * User 의 RefreshToken 이 일치하는지 확인 * @param userId 검증하려는 유저 아이디 diff --git a/src/main/java/com/tikitaka/naechinso/global/config/swagger/SwaggerConfig.java b/src/main/java/com/tikitaka/naechinso/global/config/swagger/SwaggerConfig.java index fc407d9..010b5a1 100644 --- a/src/main/java/com/tikitaka/naechinso/global/config/swagger/SwaggerConfig.java +++ b/src/main/java/com/tikitaka/naechinso/global/config/swagger/SwaggerConfig.java @@ -32,12 +32,13 @@ private ApiInfo swaggerInfo() { @Bean public Docket swaggerApi() { return new Docket(DocumentationType.SWAGGER_2) + .apiInfo(swaggerInfo()) .securityContexts(Arrays.asList(securityContext())) .securitySchemes(Arrays.asList(apiKey())) .ignoredParameterTypes(AuthenticationPrincipal.class) .consumes(getConsumeContentTypes()) .produces(getProduceContentTypes()) - .apiInfo(swaggerInfo()).select() + .select() .apis(RequestHandlerSelectors.basePackage("com.tikitaka.naechinso")) .paths(PathSelectors.any()) .build(); @@ -49,16 +50,14 @@ private SecurityContext securityContext() { .build(); } private List defaultAuth() { - AuthorizationScope authorizationScope = new AuthorizationScope( - "global", - "accessEverything" - ); + AuthorizationScope authorizationScope + = new AuthorizationScope("global", "accessEverything"); AuthorizationScope[] authorizationScopes = new AuthorizationScope[1]; authorizationScopes[0] = authorizationScope; - return Arrays.asList(new SecurityReference("Authorization", authorizationScopes)); + return Arrays.asList(new SecurityReference("JWT", authorizationScopes)); } private ApiKey apiKey() { - return new ApiKey("Authorization", "X-AUTH-TOKEN", "header"); + return new ApiKey("JWT", "Authorization", "header"); } private Set getConsumeContentTypes() { Set consumes = new HashSet<>(); diff --git a/src/main/java/com/tikitaka/naechinso/global/error/ErrorCode.java b/src/main/java/com/tikitaka/naechinso/global/error/ErrorCode.java index 870bc0d..4dd7a1c 100644 --- a/src/main/java/com/tikitaka/naechinso/global/error/ErrorCode.java +++ b/src/main/java/com/tikitaka/naechinso/global/error/ErrorCode.java @@ -20,18 +20,20 @@ public enum ErrorCode { /* Auth 관련 오류 */ + NO_TOKEN(BAD_REQUEST, "AUTH000", "토큰이 존재하지 않습니다"), EXPIRED_TOKEN(BAD_REQUEST, "AUTH001", "만료된 엑세스 토큰입니다"), INVALID_REFRESH_TOKEN(BAD_REQUEST, "AUTH002", "리프레시 토큰이 유효하지 않습니다"), MISMATCH_REFRESH_TOKEN(BAD_REQUEST, "AUTH003", "리프레시 토큰의 유저 정보가 일치하지 않습니다"), INVALID_AUTH_TOKEN(UNAUTHORIZED, "AUTH004", "권한 정보가 없는 토큰입니다"), - UNAUTHORIZED_USER(UNAUTHORIZED, "AUTH005", "현재 내 계정 정보가 존재하지 않습니다"), + UNAUTHORIZED_USER(UNAUTHORIZED, "AUTH005", "로그인이 필요합니다"), REFRESH_TOKEN_NOT_FOUND(NOT_FOUND, "AUTH006", "로그아웃 된 사용자입니다"), FORBIDDEN_USER(FORBIDDEN, "AUTH007", "권한이 없는 유저입니다"), + UNSUPPORTED_TOKEN(UNAUTHORIZED, "AUTH008", "지원하지 않는 토큰입니다"), + INVALID_SIGNATURE(UNAUTHORIZED, "AUTH009", "잘못된 JWT 서명입니다"), + MISMATCH_VERIFICATION_CODE(UNAUTHORIZED, "AUTH010", "인증번호가 일치하지 않습니다"), + EXPIRED_VERIFICATION_CODE(UNAUTHORIZED, "AUTH011", "인증번호가 만료되었습니다"), - MISMATCH_VERIFICATION_CODE(UNAUTHORIZED, "AUTH009", "인증번호가 일치하지 않습니다"), - EXPIRED_VERIFICATION_CODE(UNAUTHORIZED, "AUTH010", "인증번호가 만료되었습니다"), - - LOGIN_FAILED(UNAUTHORIZED, "AUTH008", "로그인에 실패했습니다"), + LOGIN_FAILED(UNAUTHORIZED, "AUTH012", "로그인에 실패했습니다"), /* OAuth 관련 오류 */ KAKAO_BAD_REQUEST(BAD_REQUEST, "OAUTH001", "카카오 토큰 오류"), diff --git a/src/main/java/com/tikitaka/naechinso/global/error/ErrorResponse.java b/src/main/java/com/tikitaka/naechinso/global/error/ErrorResponse.java index d89771f..1233a13 100644 --- a/src/main/java/com/tikitaka/naechinso/global/error/ErrorResponse.java +++ b/src/main/java/com/tikitaka/naechinso/global/error/ErrorResponse.java @@ -5,6 +5,7 @@ import lombok.Getter; import lombok.NoArgsConstructor; import lombok.extern.slf4j.Slf4j; +import org.json.JSONObject; import org.springframework.validation.BindingResult; import org.springframework.validation.FieldError; @@ -45,6 +46,17 @@ public static ErrorResponse of(ErrorCode errorCode, BindingResult bindingResult) .build(); } + //filter chain 을 위한 JSON 생성자 + public static JSONObject jsonOf(ErrorCode errorCode) { + JSONObject jsonObject = new JSONObject(); + jsonObject.put("timestamp", LocalDateTime.now()); + jsonObject.put("success", "false"); + jsonObject.put("message", errorCode.getDetail()); + jsonObject.put("status", errorCode.getHttpStatus().value()); + jsonObject.put("code", errorCode.getCode()); + return jsonObject; + } + @Getter @AllArgsConstructor @NoArgsConstructor diff --git a/src/main/java/com/tikitaka/naechinso/global/error/GlobalExceptionHandler.java b/src/main/java/com/tikitaka/naechinso/global/error/GlobalExceptionHandler.java index 97260a0..24f24fd 100644 --- a/src/main/java/com/tikitaka/naechinso/global/error/GlobalExceptionHandler.java +++ b/src/main/java/com/tikitaka/naechinso/global/error/GlobalExceptionHandler.java @@ -6,6 +6,7 @@ import org.springframework.http.ResponseEntity; import org.springframework.security.access.AccessDeniedException; import org.springframework.security.authentication.BadCredentialsException; +import org.springframework.security.core.AuthenticationException; import org.springframework.web.HttpRequestMethodNotSupportedException; import org.springframework.web.bind.MethodArgumentNotValidException; import org.springframework.web.bind.annotation.ExceptionHandler; From be6284f00a3862047a32d72aa0dd1ccd8e0ef791 Mon Sep 17 00:00:00 2001 From: gengminy Date: Thu, 29 Sep 2022 20:44:44 +0900 Subject: [PATCH 06/72] =?UTF-8?q?:rocket:=20feat(entity):=20=EC=97=94?= =?UTF-8?q?=ED=8B=B0=ED=8B=B0=20=EA=B5=AC=ED=98=84=20=EB=B0=8F=20=EC=97=B0?= =?UTF-8?q?=EA=B4=80=EA=B4=80=EA=B3=84=20=EC=84=A4=EC=A0=95=20#18?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../domain/member/MemberController.java | 32 ++++++-- .../domain/member/MemberService.java | 6 +- .../dto/MemberCommonJoinRequestDto.java | 1 - ...eDto.java => MemberCommonResponseDto.java} | 11 +-- .../dto/MemberDetailJoinRequestDto.java | 81 +++++++++---------- .../domain/member/entity/Member.java | 27 ++++--- .../domain/member/entity/MemberDetail.java | 18 ++++- .../naechinso/domain/point/entity/Point.java | 7 +- .../domain/recommend/RecommendController.java | 47 ++++++++++- .../domain/recommend/RecommendRepository.java | 8 +- .../domain/recommend/RecommendService.java | 51 ++++++++++++ .../domain/recommend/dto/RecommendDTO.java | 43 ++++++++++ .../dto/RecommendListResponseDTO.java | 30 +++++++ .../recommend/dto/RecommendRequestDTO.java | 40 +++++++++ .../domain/recommend/entity/Recommend.java | 27 +++++++ .../sms/SmsCertificationServiceImpl.java | 21 ++++- .../global/annotation/AuthMember.java | 12 ++- .../naechinso/global/annotation/Enum.java | 4 + .../jwt/JwtAuthenticationEntryPoint.java | 8 ++ 19 files changed, 389 insertions(+), 85 deletions(-) rename src/main/java/com/tikitaka/naechinso/domain/member/dto/{MemberCommonJoinResponseDto.java => MemberCommonResponseDto.java} (65%) create mode 100644 src/main/java/com/tikitaka/naechinso/domain/recommend/dto/RecommendDTO.java create mode 100644 src/main/java/com/tikitaka/naechinso/domain/recommend/dto/RecommendListResponseDTO.java create mode 100644 src/main/java/com/tikitaka/naechinso/domain/recommend/dto/RecommendRequestDTO.java diff --git a/src/main/java/com/tikitaka/naechinso/domain/member/MemberController.java b/src/main/java/com/tikitaka/naechinso/domain/member/MemberController.java index e27906e..d51779c 100644 --- a/src/main/java/com/tikitaka/naechinso/domain/member/MemberController.java +++ b/src/main/java/com/tikitaka/naechinso/domain/member/MemberController.java @@ -1,7 +1,7 @@ package com.tikitaka.naechinso.domain.member; import com.tikitaka.naechinso.domain.member.dto.MemberCommonJoinRequestDto; -import com.tikitaka.naechinso.domain.member.dto.MemberCommonJoinResponseDto; +import com.tikitaka.naechinso.domain.member.dto.MemberCommonResponseDto; import com.tikitaka.naechinso.domain.member.entity.Member; import com.tikitaka.naechinso.global.annotation.AuthMember; import com.tikitaka.naechinso.global.config.CommonApiResponse; @@ -11,6 +11,7 @@ import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; import org.springframework.web.bind.annotation.*; +import springfox.documentation.annotations.ApiIgnore; import javax.servlet.http.HttpServletRequest; import javax.validation.Valid; @@ -25,18 +26,35 @@ public class MemberController { @GetMapping("/") @ApiOperation(value = "유저 자신의 정보를 가져온다 (AccessToken 필요)") - public CommonApiResponse getMyInformation(HttpServletRequest request, @AuthMember Member member) { + public CommonApiResponse getMyInformation( + HttpServletRequest request, @ApiIgnore @AuthMember Member member) { + //로그인 상태가 아닌 경우 401 if (member == null) { throw new UnauthorizedException(ErrorCode.UNAUTHORIZED_USER); } - return CommonApiResponse.of(MemberCommonJoinResponseDto.of(member)); + return CommonApiResponse.of(MemberCommonResponseDto.of(member)); } - - @PostMapping("/join") - public CommonApiResponse joinCommonMember(@Valid @RequestBody MemberCommonJoinRequestDto dto) { - final MemberCommonJoinResponseDto res = memberService.joinCommonMember(dto); + @ApiOperation(value = "공통 유저를 회원가입 시킨다") + public CommonApiResponse joinCommonMember( + @Valid @RequestBody MemberCommonJoinRequestDto dto) + { + final MemberCommonResponseDto res = memberService.joinCommonMember(dto); + return CommonApiResponse.of(res); + } + + @PostMapping("/detail") + @ApiOperation(value = "회원가입 세부 정보를 입력한다 (AccessToken 필요)") + public CommonApiResponse setMemberDetail( + @Valid @RequestBody MemberCommonJoinRequestDto dto, + @ApiIgnore @AuthMember Member member) + { + //로그인 상태가 아닌 경우 401 + if (member == null) { + throw new UnauthorizedException(ErrorCode.UNAUTHORIZED_USER); + } + final MemberCommonResponseDto res = memberService.joinCommonMember(dto); return CommonApiResponse.of(res); } diff --git a/src/main/java/com/tikitaka/naechinso/domain/member/MemberService.java b/src/main/java/com/tikitaka/naechinso/domain/member/MemberService.java index cbe743f..31d68f9 100644 --- a/src/main/java/com/tikitaka/naechinso/domain/member/MemberService.java +++ b/src/main/java/com/tikitaka/naechinso/domain/member/MemberService.java @@ -1,7 +1,7 @@ package com.tikitaka.naechinso.domain.member; import com.tikitaka.naechinso.domain.member.dto.MemberCommonJoinRequestDto; -import com.tikitaka.naechinso.domain.member.dto.MemberCommonJoinResponseDto; +import com.tikitaka.naechinso.domain.member.dto.MemberCommonResponseDto; import com.tikitaka.naechinso.domain.member.entity.Member; import com.tikitaka.naechinso.global.common.response.TokenResponseDTO; import com.tikitaka.naechinso.global.config.security.MemberAdapter; @@ -30,7 +30,7 @@ public class MemberService { private final AuthenticationManagerBuilder authenticationManagerBuilder; private final JwtTokenProvider jwtTokenProvider; - public MemberCommonJoinResponseDto joinCommonMember(MemberCommonJoinRequestDto dto) { + public MemberCommonResponseDto joinCommonMember(MemberCommonJoinRequestDto dto) { //이미 존재하는 유저일 경우 400 Optional checkMember = memberRepository.findByPhone(dto.getPhone()); @@ -41,7 +41,7 @@ public MemberCommonJoinResponseDto joinCommonMember(MemberCommonJoinRequestDto d Member member = MemberCommonJoinRequestDto.toCommonMember(dto); memberRepository.save(member); - MemberCommonJoinResponseDto res = MemberCommonJoinResponseDto.of(member); + MemberCommonResponseDto res = MemberCommonResponseDto.of(member); return res; } diff --git a/src/main/java/com/tikitaka/naechinso/domain/member/dto/MemberCommonJoinRequestDto.java b/src/main/java/com/tikitaka/naechinso/domain/member/dto/MemberCommonJoinRequestDto.java index 46cba24..8645062 100644 --- a/src/main/java/com/tikitaka/naechinso/domain/member/dto/MemberCommonJoinRequestDto.java +++ b/src/main/java/com/tikitaka/naechinso/domain/member/dto/MemberCommonJoinRequestDto.java @@ -4,7 +4,6 @@ import com.tikitaka.naechinso.domain.member.entity.Member; import com.tikitaka.naechinso.global.annotation.Enum; import lombok.*; -import org.hibernate.validator.constraints.Length; import javax.validation.constraints.*; diff --git a/src/main/java/com/tikitaka/naechinso/domain/member/dto/MemberCommonJoinResponseDto.java b/src/main/java/com/tikitaka/naechinso/domain/member/dto/MemberCommonResponseDto.java similarity index 65% rename from src/main/java/com/tikitaka/naechinso/domain/member/dto/MemberCommonJoinResponseDto.java rename to src/main/java/com/tikitaka/naechinso/domain/member/dto/MemberCommonResponseDto.java index 09945ae..7a2281b 100644 --- a/src/main/java/com/tikitaka/naechinso/domain/member/dto/MemberCommonJoinResponseDto.java +++ b/src/main/java/com/tikitaka/naechinso/domain/member/dto/MemberCommonResponseDto.java @@ -4,11 +4,6 @@ import com.tikitaka.naechinso.domain.member.entity.Member; import lombok.*; -import javax.validation.constraints.NotBlank; -import javax.validation.constraints.NotNull; -import javax.validation.constraints.Pattern; -import javax.validation.constraints.Size; - /** * 추천인 및 추천 받는 사람 공통 가입을 위한 Dto입니다 * @author gengminy 220924 @@ -18,7 +13,7 @@ @Getter @Builder @ToString -public class MemberCommonJoinResponseDto { +public class MemberCommonResponseDto { private String phone; private String name; @@ -27,8 +22,8 @@ public class MemberCommonJoinResponseDto { private int age; - public static MemberCommonJoinResponseDto of(Member member) { - MemberCommonJoinResponseDto res = MemberCommonJoinResponseDto.builder() + public static MemberCommonResponseDto of(Member member) { + MemberCommonResponseDto res = MemberCommonResponseDto.builder() .phone(member.getPhone()) .name(member.getName()) .gender(member.getGender()) diff --git a/src/main/java/com/tikitaka/naechinso/domain/member/dto/MemberDetailJoinRequestDto.java b/src/main/java/com/tikitaka/naechinso/domain/member/dto/MemberDetailJoinRequestDto.java index be122c5..80d321d 100644 --- a/src/main/java/com/tikitaka/naechinso/domain/member/dto/MemberDetailJoinRequestDto.java +++ b/src/main/java/com/tikitaka/naechinso/domain/member/dto/MemberDetailJoinRequestDto.java @@ -3,7 +3,9 @@ import com.tikitaka.naechinso.domain.member.constant.Gender; import com.tikitaka.naechinso.domain.member.entity.Member; import lombok.*; +import org.hibernate.validator.constraints.Length; +import javax.persistence.Column; import javax.validation.constraints.*; /** @@ -16,61 +18,58 @@ @Builder @ToString public class MemberDetailJoinRequestDto { - @NotBlank(message = "전화번호를 입력해주세요") - @Pattern(regexp = "[0-9]{10,11}", message = "하이픈 없는 10~11자리 숫자를 입력해주세요") - private String phone; + //추천인 정보 + // - @NotBlank(message = "이름을 입력해주세요") - private String name; + @Positive(message = "키는 양수여야 합니다") + private int height; - @NotNull(message = "성별을 입력해주세요") - private Gender gender; + @NotBlank(message = "주소 정보를 입력해야 합니다") + private String address; - @Min(value = 25, message = "25-33세까지만 가입 가능합니다") - @Max(value = 33, message = "25-33세까지만 가입 가능합니다") - private int age; + @NotBlank(message = "종교 정보를 입력해야 합니다") + private String religion; - @NotNull(message = "서비스 이용약관 동의가 필요합니다") - @AssertTrue(message = "서비스 이용약관 동의가 필요합니다") - private boolean acceptsService; + @NotBlank(message = "음주 정보를 입력해야 합니다") + private String drink; - @NotNull(message = "개인정보 이용 동의가 필요합니다") - @AssertTrue(message = "개인정보 이용 동의가 필요합니다") - private boolean acceptsInfo; + @NotBlank(message = "흡연 정보를 입력해야 합니다") + private String smoke; - @NotNull(message = "종교 정보 제공 동의가 필요합니다") - @AssertTrue(message = "종교 정보 제공 동의가 필요합니다") - private boolean acceptsReligion; + @Length(max = 4, message = "올바를 MBTI 정보를 입력하세요") + private String mbti = ""; - @NotNull(message = "위치 정보 제공 동의 여부가 필요합니다") - private boolean acceptsLocation; + @NotBlank(message = "성격 정보를 입력해야 합니다") + private String personality; - @NotNull(message = "마케팅 동의 여부가 필요합니다") - private boolean acceptsMarketing; + @NotBlank(message = "자기 소개를 입력해야 합니다") + private String introduce = ""; - @NotBlank(message = "직장명을 입력해주세요") - private String jobName; + @NotBlank(message = "취미 정보를 입력해야 합니다") + private String hobby = ""; - @NotBlank(message = "직장 부서를 입력해주세요") - private String jobPart; + @NotBlank(message = "연애 스타일을 입력해야 합니다") + private String style = ""; + + @NotBlank(message = "사진을 업로드해야 합니다") + private String picture; + + @Builder.Default + private Long point = 0L; + + + private String school; + + + private String major; + + + private String eduLevel; - @NotBlank(message = "직장 위치를 입력해주세요") - private String jobLocation; public static Member toCommonMember(MemberDetailJoinRequestDto dto) { Member member = Member.builder() - .phone(dto.phone) - .name(dto.name) - .gender(dto.gender) - .age(dto.age) - .acceptsService(dto.acceptsService) - .acceptsInfo(dto.acceptsInfo) - .acceptsReligion(dto.acceptsReligion) - .acceptsLocation(dto.acceptsLocation) - .acceptsMarketing(dto.acceptsMarketing) - .jobName(dto.jobName) - .jobPart(dto.jobPart) - .jobLocation(dto.jobLocation) + .build(); return member; diff --git a/src/main/java/com/tikitaka/naechinso/domain/member/entity/Member.java b/src/main/java/com/tikitaka/naechinso/domain/member/entity/Member.java index dcea98c..02a79e0 100644 --- a/src/main/java/com/tikitaka/naechinso/domain/member/entity/Member.java +++ b/src/main/java/com/tikitaka/naechinso/domain/member/entity/Member.java @@ -1,10 +1,14 @@ package com.tikitaka.naechinso.domain.member.entity; import com.tikitaka.naechinso.domain.member.constant.Gender; +import com.tikitaka.naechinso.domain.point.entity.Point; +import com.tikitaka.naechinso.domain.recommend.entity.Recommend; import com.tikitaka.naechinso.global.config.entity.BaseEntity; import lombok.*; import javax.persistence.*; +import java.util.ArrayList; +import java.util.List; /** * 멤버 공통 정보를 담당하는 엔티티입니다 @@ -38,23 +42,23 @@ public class Member extends BaseEntity { @Column(name = "mem_age") private int age; - @Column(name = "mem_accpets_service") + @Column(name = "mem_accepts_service") @Builder.Default private boolean acceptsService = false; - @Column(name = "mem_accpets_info") + @Column(name = "mem_accepts_info") @Builder.Default private boolean acceptsInfo = false; - @Column(name = "mem_accpets_religion") + @Column(name = "mem_accepts_religion") @Builder.Default private boolean acceptsReligion = false; - @Column(name = "mem_accpets_location") + @Column(name = "mem_accepts_location") @Builder.Default private boolean acceptsLocation = false; - @Column(name = "mem_accpets_marketing") + @Column(name = "mem_accepts_marketing") @Builder.Default private boolean acceptsMarketing = false; @@ -72,12 +76,13 @@ public class Member extends BaseEntity { @JoinColumn(name = "mem_detail") private MemberDetail detail; + //소개해준 사람들 -> recommend 로 넣으면 됨 + //mapped by 에는 연관관계 엔티티의 필드명을 적어줌 + @OneToMany(mappedBy = "sender") + private List recommends = new ArrayList<>(); + //소개해준 사람들 -> recommend 로 넣으면 됨 + @OneToOne(mappedBy = "receiver") + private Recommend recommend_received; - -// //소개해준 사람들 -// @OneToMany -// @JoinColumn -// @Builder.Default -// private List receivers = new ArrayList<>(); } diff --git a/src/main/java/com/tikitaka/naechinso/domain/member/entity/MemberDetail.java b/src/main/java/com/tikitaka/naechinso/domain/member/entity/MemberDetail.java index 7caf770..29cc602 100644 --- a/src/main/java/com/tikitaka/naechinso/domain/member/entity/MemberDetail.java +++ b/src/main/java/com/tikitaka/naechinso/domain/member/entity/MemberDetail.java @@ -1,10 +1,13 @@ package com.tikitaka.naechinso.domain.member.entity; +import com.tikitaka.naechinso.domain.point.entity.Point; import com.tikitaka.naechinso.global.config.entity.BaseEntity; import com.tikitaka.naechinso.global.config.entity.BaseTimeEntity; import lombok.*; import javax.persistence.*; +import java.util.ArrayList; +import java.util.List; /** * 추천 받은 멤버 가입 정보를 담당하는 엔티티입니다 @@ -30,7 +33,7 @@ public class MemberDetail extends BaseEntity { // private Member recommender; @Column(name = "mem_height") - private Integer height; + private int height; @Column(name = "mem_address") private String address; @@ -55,6 +58,14 @@ public class MemberDetail extends BaseEntity { @Builder.Default private String introduce = ""; + @Column(name = "mem_hobby") + @Builder.Default + private String hobby = ""; + + @Column(name = "mem_style") + @Builder.Default + private String style = ""; + @Column(name = "mem_picture") private String picture; @@ -70,8 +81,9 @@ public class MemberDetail extends BaseEntity { @Column(name = "mem_edu_level") private String eduLevel; - - + // 포인트 내역 + @OneToMany(mappedBy = "member") + private List points = new ArrayList<>(); // Member Entity 와 1:1 조인 // Member PK 그대로 사용 diff --git a/src/main/java/com/tikitaka/naechinso/domain/point/entity/Point.java b/src/main/java/com/tikitaka/naechinso/domain/point/entity/Point.java index 21e168e..86ffcce 100644 --- a/src/main/java/com/tikitaka/naechinso/domain/point/entity/Point.java +++ b/src/main/java/com/tikitaka/naechinso/domain/point/entity/Point.java @@ -34,8 +34,7 @@ public class Point extends BaseEntity { @Column(name = "poi_type") private String type; -// -// @ManyToOne -// @PrimaryKeyJoinColumn -// private Member member; + @ManyToOne(fetch = FetchType.LAZY) + @JoinColumn(name = "mem_id") + private MemberDetail member; } diff --git a/src/main/java/com/tikitaka/naechinso/domain/recommend/RecommendController.java b/src/main/java/com/tikitaka/naechinso/domain/recommend/RecommendController.java index fd454c6..eae4116 100644 --- a/src/main/java/com/tikitaka/naechinso/domain/recommend/RecommendController.java +++ b/src/main/java/com/tikitaka/naechinso/domain/recommend/RecommendController.java @@ -1,7 +1,52 @@ package com.tikitaka.naechinso.domain.recommend; +import com.tikitaka.naechinso.domain.member.dto.MemberCommonResponseDto; +import com.tikitaka.naechinso.domain.member.entity.Member; +import com.tikitaka.naechinso.domain.recommend.dto.RecommendListResponseDTO; +import com.tikitaka.naechinso.domain.recommend.dto.RecommendRequestDTO; +import com.tikitaka.naechinso.global.annotation.AuthMember; +import com.tikitaka.naechinso.global.config.CommonApiResponse; +import com.tikitaka.naechinso.global.error.ErrorCode; +import com.tikitaka.naechinso.global.error.exception.UnauthorizedException; +import io.swagger.annotations.ApiOperation; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; import org.springframework.stereotype.Controller; +import org.springframework.web.bind.annotation.*; +import springfox.documentation.annotations.ApiIgnore; -@Controller +import javax.servlet.http.HttpServletRequest; + +@Slf4j +@RestController +@RequestMapping("/recommend") +@RequiredArgsConstructor public class RecommendController { + + private final RecommendService recommendService; + + @GetMapping("/") + @ApiOperation(value = "내 추천사 정보를 가져온다 (AccessToken 필요)") + public CommonApiResponse getRecommends( + HttpServletRequest request, + @ApiIgnore @AuthMember Member member) + { + if (member == null) { + throw new UnauthorizedException(ErrorCode.UNAUTHORIZED_USER); + } + return CommonApiResponse.of(recommendService.getRecommendList(member)); + } + + @PostMapping("/") + @ApiOperation(value = "추천사를 작성한다 (AccessToken 필요)") + public CommonApiResponse writeRecommend( + HttpServletRequest request, + @RequestBody RecommendRequestDTO dto, + @ApiIgnore @AuthMember Member member) + { + if (member == null) { + throw new UnauthorizedException(ErrorCode.UNAUTHORIZED_USER); + } + return CommonApiResponse.of(MemberCommonResponseDto.of(member)); + } } diff --git a/src/main/java/com/tikitaka/naechinso/domain/recommend/RecommendRepository.java b/src/main/java/com/tikitaka/naechinso/domain/recommend/RecommendRepository.java index fb80185..5bb4fb8 100644 --- a/src/main/java/com/tikitaka/naechinso/domain/recommend/RecommendRepository.java +++ b/src/main/java/com/tikitaka/naechinso/domain/recommend/RecommendRepository.java @@ -1,4 +1,10 @@ package com.tikitaka.naechinso.domain.recommend; -public interface RecommendRepository { +import com.tikitaka.naechinso.domain.member.entity.MemberDetail; +import com.tikitaka.naechinso.domain.recommend.entity.Recommend; +import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.stereotype.Repository; + +@Repository +public interface RecommendRepository extends JpaRepository { } diff --git a/src/main/java/com/tikitaka/naechinso/domain/recommend/RecommendService.java b/src/main/java/com/tikitaka/naechinso/domain/recommend/RecommendService.java index 42c1315..fb33d0a 100644 --- a/src/main/java/com/tikitaka/naechinso/domain/recommend/RecommendService.java +++ b/src/main/java/com/tikitaka/naechinso/domain/recommend/RecommendService.java @@ -1,7 +1,58 @@ package com.tikitaka.naechinso.domain.recommend; +import com.tikitaka.naechinso.domain.member.MemberRepository; +import com.tikitaka.naechinso.domain.member.entity.Member; +import com.tikitaka.naechinso.domain.recommend.dto.RecommendListResponseDTO; +import com.tikitaka.naechinso.domain.recommend.dto.RecommendRequestDTO; +import com.tikitaka.naechinso.domain.recommend.entity.Recommend; +import lombok.RequiredArgsConstructor; import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +import java.util.Optional; @Service +@RequiredArgsConstructor +@Transactional public class RecommendService { + + private final RecommendRepository recommendRepository; + private final MemberRepository memberRepository; + + public RecommendListResponseDTO getRecommendList(Member member) { + return RecommendListResponseDTO.of(member); + } + + /** + * 추천사를 작성한다 + * @param sender 로그인 여부 및 추천인 정보 가져옴 + * @param dto 추천하려는 사람의 정보 dto + * */ + public RecommendListResponseDTO recommendMember( + Member sender, + RecommendRequestDTO dto) + { + //작성자가 회원일 경우, + //추천할 사람이 이미 가입하여 요청했을 경우, + //둘 모두 회원이 아닐 경우 + + Optional checkMember = memberRepository.findByPhone(dto.getPhone()); + Member receiver; + //상대가 이미 있는 유저면 FK 로 저장 + if (checkMember.isPresent()) { + receiver = checkMember.get(); + } + //상대가 없는 유저면 새로 만든 후 FK 저장 + else { + receiver = Member.builder() + .build(); + } + + Recommend recommend = Recommend.builder() + .sender(sender) + .phone(receiver.getPhone()) + + .build(); + return RecommendListResponseDTO.of(receiver); + } } diff --git a/src/main/java/com/tikitaka/naechinso/domain/recommend/dto/RecommendDTO.java b/src/main/java/com/tikitaka/naechinso/domain/recommend/dto/RecommendDTO.java new file mode 100644 index 0000000..2bf4c39 --- /dev/null +++ b/src/main/java/com/tikitaka/naechinso/domain/recommend/dto/RecommendDTO.java @@ -0,0 +1,43 @@ +package com.tikitaka.naechinso.domain.recommend.dto; + +import com.tikitaka.naechinso.domain.member.constant.Gender; +import com.tikitaka.naechinso.domain.member.entity.Member; +import com.tikitaka.naechinso.domain.recommend.entity.Recommend; +import lombok.*; + +import javax.persistence.*; + +@AllArgsConstructor +@NoArgsConstructor +@Getter +@Builder +@ToString +public class RecommendDTO { + + private String phone; + + private Member sender; + + private Member receiver; + + private String name; + + private Gender gender; + + private String meet; + + private String appeal; + + + public static RecommendDTO of(Recommend recommend) { + return RecommendDTO.builder() + .phone(recommend.getPhone()) + .sender(recommend.getSender()) + .receiver(recommend.getReceiver()) + .name(recommend.getName()) + .gender(recommend.getGender()) + .meet(recommend.getMeet()) + .appeal(recommend.getAppeal()) + .build(); + } +} diff --git a/src/main/java/com/tikitaka/naechinso/domain/recommend/dto/RecommendListResponseDTO.java b/src/main/java/com/tikitaka/naechinso/domain/recommend/dto/RecommendListResponseDTO.java new file mode 100644 index 0000000..609c920 --- /dev/null +++ b/src/main/java/com/tikitaka/naechinso/domain/recommend/dto/RecommendListResponseDTO.java @@ -0,0 +1,30 @@ +package com.tikitaka.naechinso.domain.recommend.dto; + +import com.tikitaka.naechinso.domain.member.entity.Member; +import com.tikitaka.naechinso.domain.recommend.entity.Recommend; +import lombok.*; + +import java.util.ArrayList; +import java.util.List; + +@AllArgsConstructor +@NoArgsConstructor +@Getter +@Builder +@ToString +public class RecommendListResponseDTO { + List recommends = new ArrayList<>(); + + + public static RecommendListResponseDTO of(Member member) { + List recommendDTOList = new ArrayList<>(); + + member.getRecommends().stream().forEach(recommend -> + recommendDTOList.add(RecommendDTO.of(recommend)) + ); + + return RecommendListResponseDTO.builder() + .recommends(recommendDTOList) + .build(); + } +} diff --git a/src/main/java/com/tikitaka/naechinso/domain/recommend/dto/RecommendRequestDTO.java b/src/main/java/com/tikitaka/naechinso/domain/recommend/dto/RecommendRequestDTO.java new file mode 100644 index 0000000..5b5a242 --- /dev/null +++ b/src/main/java/com/tikitaka/naechinso/domain/recommend/dto/RecommendRequestDTO.java @@ -0,0 +1,40 @@ +package com.tikitaka.naechinso.domain.recommend.dto; + +import com.tikitaka.naechinso.domain.member.constant.Gender; +import com.tikitaka.naechinso.global.annotation.Enum; +import lombok.*; + +import javax.validation.constraints.Max; +import javax.validation.constraints.Min; +import javax.validation.constraints.NotBlank; +import javax.validation.constraints.Pattern; + +@AllArgsConstructor +@NoArgsConstructor +@Getter +@Builder +@ToString +public class RecommendRequestDTO { + @NotBlank(message = "친구의 전화번호를 입력해주세요") + @Pattern(regexp = "[0-9]{10,11}", message = "하이픈 없는 10~11자리 숫자를 입력해주세요") + private String phone; + + @NotBlank(message = "친구의 이름을 입력해주세요") + private String name; + + @Enum(enumClass = Gender.class, message = "친구의 성별 입력이 올바르지 않습니다. M 또는 W가 필요합니다") + private Gender gender; + + @Min(value = 25, message = "25-33세까지만 추천 및 가입 가능합니다") + @Max(value = 33, message = "25-33세까지만 추천 및 가입 가능합니다") + private int age; + + @NotBlank(message = "만나게 된 계기를 입력해주세요") + private String meet; + + @NotBlank(message = "친구의 성격 키워드를 입력해주세요") + private String personality; + + @NotBlank(message = "친구의 매력을 입력해주세요") + private String appeal; +} diff --git a/src/main/java/com/tikitaka/naechinso/domain/recommend/entity/Recommend.java b/src/main/java/com/tikitaka/naechinso/domain/recommend/entity/Recommend.java index 7fe04cb..dee7999 100644 --- a/src/main/java/com/tikitaka/naechinso/domain/recommend/entity/Recommend.java +++ b/src/main/java/com/tikitaka/naechinso/domain/recommend/entity/Recommend.java @@ -1,5 +1,7 @@ package com.tikitaka.naechinso.domain.recommend.entity; +import com.tikitaka.naechinso.domain.member.constant.Gender; +import com.tikitaka.naechinso.domain.member.entity.Member; import com.tikitaka.naechinso.global.config.entity.BaseEntity; import com.tikitaka.naechinso.global.config.entity.BaseTimeEntity; import lombok.*; @@ -23,4 +25,29 @@ public class Recommend extends BaseEntity { @GeneratedValue @Column(name = "rec_id") private Long id; + + @ManyToOne(fetch = FetchType.LAZY) + @JoinColumn(name = "mem_id") + private Member sender; + + /* 받는 사람이 아직 가입 안했으면 NULL 일수도 있음 */ + @OneToOne + @JoinColumn(name = "rec_target_id") + private Member receiver; + + @Column(name = "rec_name") + private String name; + + @Column(name = "rec_gender") + @Enumerated(EnumType.STRING) + private Gender gender; + + @Column(name = "rec_meet") + private String meet; + + @Column(name = "rec_appeal") + private String appeal; + + @Column(name = "rec_phone") + private String phone; } diff --git a/src/main/java/com/tikitaka/naechinso/domain/sms/SmsCertificationServiceImpl.java b/src/main/java/com/tikitaka/naechinso/domain/sms/SmsCertificationServiceImpl.java index 1ead487..1f47e92 100644 --- a/src/main/java/com/tikitaka/naechinso/domain/sms/SmsCertificationServiceImpl.java +++ b/src/main/java/com/tikitaka/naechinso/domain/sms/SmsCertificationServiceImpl.java @@ -90,7 +90,7 @@ public String sendVerificationMessage(String to) { /** * 인증번호를 검증한다 * @param smsCertificationRequestDto {phoneNumber: 휴대폰 번호, code: 인증번호} - * @return 전송 성공시 메세지 + * @return TokenResponseDTO { accessToken, refreshToken } */ @Override public TokenResponseDTO verifyCode(SmsCertificationRequestDTO smsCertificationRequestDto) { @@ -110,12 +110,31 @@ public TokenResponseDTO verifyCode(SmsCertificationRequestDTO smsCertificationRe //redis 인증 필터 성공하면 try { + /* VERIFY FLOW + * -> 아직 MemberDetail 작성한 회원이 아닐 경우 + * 1. 이미 추천사를 받은 신규회원 + * 2. 추천사를 받아야 하는 신규회원 + * 3. 추천사 써주려는 신규회원 + * 4. 추천 요청을 받아서 추천사를 써주는 신규회원 + * * 입력이 다 되었는지 검증, 안되면 register 토큰 발급 + * + * -> MemberDetail 검증 완료된 회원 + * 5. 즉시 마이페이지 이동 + * */ + + //가입 안된 회원일 경우 null 리턴 Optional checkMember = memberRepository.findByPhone(phoneNumber); if (checkMember.isEmpty()) { return null; } + if (checkMember.get().getDetail() != null) { + System.out.println("checkMember.get().getDetail() = " + checkMember.get().getDetail()); + } else { + System.out.println("detail is null"); + } + //이미 가입한 회원이면 //인증한 휴대폰 번호로 로그인 후 토큰 생성 TokenResponseDTO tokenResponseDTO = memberService.login(phoneNumber); diff --git a/src/main/java/com/tikitaka/naechinso/global/annotation/AuthMember.java b/src/main/java/com/tikitaka/naechinso/global/annotation/AuthMember.java index de5cec8..230c3ab 100644 --- a/src/main/java/com/tikitaka/naechinso/global/annotation/AuthMember.java +++ b/src/main/java/com/tikitaka/naechinso/global/annotation/AuthMember.java @@ -1,18 +1,22 @@ package com.tikitaka.naechinso.global.annotation; import org.springframework.security.core.annotation.AuthenticationPrincipal; +import springfox.documentation.annotations.ApiIgnore; import java.lang.annotation.ElementType; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target; -/** - * request 의 Authorization 헤더를 가지고 +/* +* request 의 Authorization 헤더를 가지고 * JwtAuthenticationFilter 를 통과하면서 - * SecurityContextHolder 에 로그인 된 유저의 + * SecurityContextHolder 에 로그인 된 유저의 ... +* */ + +/** * UserDetails 의 커스텀 구현체 MemberAdapter 를 가져온 후 - * member property 를 추출하는 어노테이션 + * member 객체 프로퍼티를 추출하는 어노테이션 * @author gengimny 220926 * */ @Target(ElementType.PARAMETER) diff --git a/src/main/java/com/tikitaka/naechinso/global/annotation/Enum.java b/src/main/java/com/tikitaka/naechinso/global/annotation/Enum.java index eabebdf..6832a19 100644 --- a/src/main/java/com/tikitaka/naechinso/global/annotation/Enum.java +++ b/src/main/java/com/tikitaka/naechinso/global/annotation/Enum.java @@ -7,6 +7,10 @@ import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target; +/** + * RequestBody 의 Enum 검증을 위한 어노테이션 입니다 + * @author gengminy 220927 + * */ /* 해당 annotation이 실행 할 ConstraintValidator 구현체를 `EnumValidator`로 지정합니다. */ @Constraint(validatedBy = {EnumValidator.class}) /* 해당 annotation은 메소드, 필드, 파라미터에 적용 할 수 있습니다. */ diff --git a/src/main/java/com/tikitaka/naechinso/global/config/security/jwt/JwtAuthenticationEntryPoint.java b/src/main/java/com/tikitaka/naechinso/global/config/security/jwt/JwtAuthenticationEntryPoint.java index 8859703..e54eec2 100644 --- a/src/main/java/com/tikitaka/naechinso/global/config/security/jwt/JwtAuthenticationEntryPoint.java +++ b/src/main/java/com/tikitaka/naechinso/global/config/security/jwt/JwtAuthenticationEntryPoint.java @@ -13,6 +13,12 @@ import javax.servlet.http.HttpServletResponse; import java.io.IOException; + +/** + * ControllerAdvice 에서는 Spring Security 예외를 잡아낼 수 없기 때문에 + * AuthenticationEntryPoint 구현체를 통해 예외처리를 커스텀한다 + * @author gengminy 220926 + * */ @Slf4j @Component public class JwtAuthenticationEntryPoint implements AuthenticationEntryPoint { @@ -22,8 +28,10 @@ public void commence( HttpServletResponse response, AuthenticationException e ) throws IOException { + String exception = (String)request.getAttribute("exception"); + //토큰이 없을 경우 if(exception == null || exception.equals(ErrorCode.NO_TOKEN.getCode())) { setResponse(response, ErrorCode.NO_TOKEN); } From 229b678816cff38cb951146a0b5beb7b90cd1018 Mon Sep 17 00:00:00 2001 From: gengminy Date: Fri, 30 Sep 2022 00:30:53 +0900 Subject: [PATCH 07/72] =?UTF-8?q?:rocket:=20feat(user):=20=EB=A9=A4?= =?UTF-8?q?=EB=B2=84=20=EB=94=94=ED=85=8C=EC=9D=BC=20=EC=84=A4=EC=A0=95=20?= =?UTF-8?q?=EB=B0=8F=20=EC=A1=B0=ED=9A=8C=20=EA=B5=AC=ED=98=84=20#18?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../domain/member/MemberController.java | 35 +++++-- .../domain/member/MemberService.java | 36 ++++++- .../dto/MemberCommonJoinRequestDto.java | 8 ++ .../domain/member/dto/MemberDTO.java | 4 + .../dto/MemberDetailJoinRequestDto.java | 14 +-- .../member/dto/MemberDetailResponseDto.java | 98 +++++++++++++++++++ .../domain/member/entity/Member.java | 6 ++ .../domain/member/entity/MemberDetail.java | 46 ++++++++- .../domain/recommend/RecommendService.java | 16 ++- .../recommend/dto/RecommendRequestDTO.java | 3 + .../sms/dto/SmsCertificationRequestDTO.java | 3 + .../dto/SmsVerificationCodeRequestDTO.java | 2 + 12 files changed, 253 insertions(+), 18 deletions(-) create mode 100644 src/main/java/com/tikitaka/naechinso/domain/member/dto/MemberDTO.java create mode 100644 src/main/java/com/tikitaka/naechinso/domain/member/dto/MemberDetailResponseDto.java diff --git a/src/main/java/com/tikitaka/naechinso/domain/member/MemberController.java b/src/main/java/com/tikitaka/naechinso/domain/member/MemberController.java index d51779c..fdebfa5 100644 --- a/src/main/java/com/tikitaka/naechinso/domain/member/MemberController.java +++ b/src/main/java/com/tikitaka/naechinso/domain/member/MemberController.java @@ -2,6 +2,8 @@ import com.tikitaka.naechinso.domain.member.dto.MemberCommonJoinRequestDto; import com.tikitaka.naechinso.domain.member.dto.MemberCommonResponseDto; +import com.tikitaka.naechinso.domain.member.dto.MemberDetailJoinRequestDto; +import com.tikitaka.naechinso.domain.member.dto.MemberDetailResponseDto; import com.tikitaka.naechinso.domain.member.entity.Member; import com.tikitaka.naechinso.global.annotation.AuthMember; import com.tikitaka.naechinso.global.config.CommonApiResponse; @@ -15,6 +17,7 @@ import javax.servlet.http.HttpServletRequest; import javax.validation.Valid; +import java.util.List; @Slf4j @RestController @@ -25,7 +28,7 @@ public class MemberController { private final MemberService memberService; @GetMapping("/") - @ApiOperation(value = "유저 자신의 정보를 가져온다 (AccessToken 필요)") + @ApiOperation(value = "유저 자신의 모든 정보를 가져온다 (AccessToken 필요)") public CommonApiResponse getMyInformation( HttpServletRequest request, @ApiIgnore @AuthMember Member member) { //로그인 상태가 아닌 경우 401 @@ -36,28 +39,48 @@ public CommonApiResponse getMyInformation( } @PostMapping("/join") - @ApiOperation(value = "공통 유저를 회원가입 시킨다") + @ApiOperation(value = "공통 유저를 기본 정보로 회원가입 시킨다") public CommonApiResponse joinCommonMember( @Valid @RequestBody MemberCommonJoinRequestDto dto) { - final MemberCommonResponseDto res = memberService.joinCommonMember(dto); + final MemberCommonResponseDto res = memberService.createCommonMember(dto); + return CommonApiResponse.of(res); + } + + @GetMapping("/detail") + @ApiOperation(value = "회원가입 세부 정보를 가져온다 (AccessToken 필요)") + public CommonApiResponse getMemberDetail( + @ApiIgnore @AuthMember Member member) + { + //로그인 상태가 아닌 경우 401 + if (member == null) { + throw new UnauthorizedException(ErrorCode.UNAUTHORIZED_USER); + } + final MemberDetailResponseDto res = memberService.readDetail(member); return CommonApiResponse.of(res); } @PostMapping("/detail") @ApiOperation(value = "회원가입 세부 정보를 입력한다 (AccessToken 필요)") - public CommonApiResponse setMemberDetail( - @Valid @RequestBody MemberCommonJoinRequestDto dto, + public CommonApiResponse setMemberDetail( + @Valid @RequestBody MemberDetailJoinRequestDto dto, @ApiIgnore @AuthMember Member member) { //로그인 상태가 아닌 경우 401 if (member == null) { throw new UnauthorizedException(ErrorCode.UNAUTHORIZED_USER); } - final MemberCommonResponseDto res = memberService.joinCommonMember(dto); + final MemberDetailResponseDto res = memberService.createDetail(member, dto); return CommonApiResponse.of(res); } + //페이징 처리 추가할 예정 + @GetMapping("/find") + @ApiOperation(value = "현재 가입한 모든 유저를 불러온다") + public CommonApiResponse> getMyInformation() { + return CommonApiResponse.of(memberService.findAll()); + } + // @PostMapping("/login") diff --git a/src/main/java/com/tikitaka/naechinso/domain/member/MemberService.java b/src/main/java/com/tikitaka/naechinso/domain/member/MemberService.java index 31d68f9..eb096d1 100644 --- a/src/main/java/com/tikitaka/naechinso/domain/member/MemberService.java +++ b/src/main/java/com/tikitaka/naechinso/domain/member/MemberService.java @@ -2,13 +2,17 @@ import com.tikitaka.naechinso.domain.member.dto.MemberCommonJoinRequestDto; import com.tikitaka.naechinso.domain.member.dto.MemberCommonResponseDto; +import com.tikitaka.naechinso.domain.member.dto.MemberDetailJoinRequestDto; +import com.tikitaka.naechinso.domain.member.dto.MemberDetailResponseDto; import com.tikitaka.naechinso.domain.member.entity.Member; +import com.tikitaka.naechinso.domain.member.entity.MemberDetail; import com.tikitaka.naechinso.global.common.response.TokenResponseDTO; import com.tikitaka.naechinso.global.config.security.MemberAdapter; import com.tikitaka.naechinso.global.config.security.dto.JwtDTO; import com.tikitaka.naechinso.global.config.security.jwt.JwtTokenProvider; import com.tikitaka.naechinso.global.error.ErrorCode; import com.tikitaka.naechinso.global.error.exception.BadRequestException; +import com.tikitaka.naechinso.global.error.exception.NotFoundException; import lombok.RequiredArgsConstructor; import org.springframework.security.authentication.UsernamePasswordAuthenticationToken; import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder; @@ -17,8 +21,10 @@ import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; +import java.util.Arrays; import java.util.List; import java.util.Optional; +import java.util.stream.Collectors; @Service @RequiredArgsConstructor @@ -30,7 +36,14 @@ public class MemberService { private final AuthenticationManagerBuilder authenticationManagerBuilder; private final JwtTokenProvider jwtTokenProvider; - public MemberCommonResponseDto joinCommonMember(MemberCommonJoinRequestDto dto) { + public List findAll() { + List memberList = memberRepository.findAll().stream() + .map(member -> MemberCommonResponseDto.of(member)).collect(Collectors.toList()); + return memberList; + } + + + public MemberCommonResponseDto createCommonMember(MemberCommonJoinRequestDto dto) { //이미 존재하는 유저일 경우 400 Optional checkMember = memberRepository.findByPhone(dto.getPhone()); @@ -47,7 +60,6 @@ public MemberCommonResponseDto joinCommonMember(MemberCommonJoinRequestDto dto) public TokenResponseDTO login(String phone) { - System.out.println("phone = " + phone); Member checkMember = memberRepository.findByPhone(phone) .orElseThrow(() -> new BadRequestException(ErrorCode.USER_NOT_FOUND)); @@ -63,6 +75,26 @@ public TokenResponseDTO login(String phone) { return tokenResponseDTO; } + + public MemberDetailResponseDto readDetail(Member member) { +// +// Member checkMember = memberRepository.findByPhone(phone) +// .orElseThrow(() -> new BadRequestException(ErrorCode.USER_NOT_FOUND)); + + MemberDetailResponseDto dto = MemberDetailResponseDto.of(member); + + return dto; + } + + public MemberDetailResponseDto createDetail(Member authMember, MemberDetailJoinRequestDto dto) { + //영속성 유지를 위한 fetch + Member member = memberRepository.findById(authMember.getId()) + .orElseThrow(() -> new NotFoundException(ErrorCode.USER_NOT_FOUND)); + MemberDetail detail = MemberDetail.of(member, dto); + memberDetailRepository.save(detail); + return MemberDetailResponseDto.of(detail); + } + // // public MemberCommonJoinResponseDto joinMemberWithDetail(MemberCommonJoinRequestDto dto) { // //이미 존재하는 유저일 경우 400 diff --git a/src/main/java/com/tikitaka/naechinso/domain/member/dto/MemberCommonJoinRequestDto.java b/src/main/java/com/tikitaka/naechinso/domain/member/dto/MemberCommonJoinRequestDto.java index 8645062..ad4ea66 100644 --- a/src/main/java/com/tikitaka/naechinso/domain/member/dto/MemberCommonJoinRequestDto.java +++ b/src/main/java/com/tikitaka/naechinso/domain/member/dto/MemberCommonJoinRequestDto.java @@ -3,6 +3,7 @@ import com.tikitaka.naechinso.domain.member.constant.Gender; import com.tikitaka.naechinso.domain.member.entity.Member; import com.tikitaka.naechinso.global.annotation.Enum; +import io.swagger.annotations.ApiModelProperty; import lombok.*; import javax.validation.constraints.*; @@ -17,16 +18,20 @@ @Builder @ToString public class MemberCommonJoinRequestDto { + @ApiModelProperty(example = "01010001000") @NotBlank(message = "전화번호를 입력해주세요") @Pattern(regexp = "[0-9]{10,11}", message = "하이픈 없는 10~11자리 숫자를 입력해주세요") private String phone; + @ApiModelProperty(example = "닉") @NotBlank(message = "이름을 입력해주세요") private String name; + @ApiModelProperty(example = "M") @Enum(enumClass = Gender.class, message = "성별 입력이 올바르지 않습니다. M 또는 W가 필요합니다") private Gender gender; + @ApiModelProperty(example = "25") @Min(value = 25, message = "25-33세까지만 가입 가능합니다") @Max(value = 33, message = "25-33세까지만 가입 가능합니다") private int age; @@ -49,12 +54,15 @@ public class MemberCommonJoinRequestDto { @NotNull(message = "마케팅 동의 여부가 필요합니다") private boolean acceptsMarketing; + @ApiModelProperty(example = "카카오") @NotBlank(message = "직장명을 입력해주세요") private String jobName; + @ApiModelProperty(example = "개발자") @NotBlank(message = "직장 부서를 입력해주세요") private String jobPart; + @ApiModelProperty(example = "판교") @NotBlank(message = "직장 위치를 입력해주세요") private String jobLocation; diff --git a/src/main/java/com/tikitaka/naechinso/domain/member/dto/MemberDTO.java b/src/main/java/com/tikitaka/naechinso/domain/member/dto/MemberDTO.java new file mode 100644 index 0000000..dbbc0b3 --- /dev/null +++ b/src/main/java/com/tikitaka/naechinso/domain/member/dto/MemberDTO.java @@ -0,0 +1,4 @@ +package com.tikitaka.naechinso.domain.member.dto; + +public class MemberDTO { +} diff --git a/src/main/java/com/tikitaka/naechinso/domain/member/dto/MemberDetailJoinRequestDto.java b/src/main/java/com/tikitaka/naechinso/domain/member/dto/MemberDetailJoinRequestDto.java index 80d321d..ade8873 100644 --- a/src/main/java/com/tikitaka/naechinso/domain/member/dto/MemberDetailJoinRequestDto.java +++ b/src/main/java/com/tikitaka/naechinso/domain/member/dto/MemberDetailJoinRequestDto.java @@ -2,6 +2,7 @@ import com.tikitaka.naechinso.domain.member.constant.Gender; import com.tikitaka.naechinso.domain.member.entity.Member; +import io.swagger.annotations.ApiModelProperty; import lombok.*; import org.hibernate.validator.constraints.Length; @@ -20,10 +21,11 @@ public class MemberDetailJoinRequestDto { //추천인 정보 // - + @ApiModelProperty(example = "180") @Positive(message = "키는 양수여야 합니다") private int height; + @ApiModelProperty(example = "서울시 강남구") @NotBlank(message = "주소 정보를 입력해야 합니다") private String address; @@ -36,6 +38,7 @@ public class MemberDetailJoinRequestDto { @NotBlank(message = "흡연 정보를 입력해야 합니다") private String smoke; + @ApiModelProperty(example = "ESTJ") @Length(max = 4, message = "올바를 MBTI 정보를 입력하세요") private String mbti = ""; @@ -54,16 +57,13 @@ public class MemberDetailJoinRequestDto { @NotBlank(message = "사진을 업로드해야 합니다") private String picture; - @Builder.Default - private Long point = 0L; - - + @ApiModelProperty(example = "서울") private String school; - + @ApiModelProperty(example = "컴퓨터공학과") private String major; - + @ApiModelProperty(example = "대학교") private String eduLevel; diff --git a/src/main/java/com/tikitaka/naechinso/domain/member/dto/MemberDetailResponseDto.java b/src/main/java/com/tikitaka/naechinso/domain/member/dto/MemberDetailResponseDto.java new file mode 100644 index 0000000..193610a --- /dev/null +++ b/src/main/java/com/tikitaka/naechinso/domain/member/dto/MemberDetailResponseDto.java @@ -0,0 +1,98 @@ +package com.tikitaka.naechinso.domain.member.dto; + +import com.tikitaka.naechinso.domain.member.constant.Gender; +import com.tikitaka.naechinso.domain.member.entity.Member; +import com.tikitaka.naechinso.domain.member.entity.MemberDetail; +import lombok.*; + +import javax.persistence.Column; +import javax.persistence.EnumType; +import javax.persistence.Enumerated; + +/** + * 추천인 및 추천 받는 사람 공통 가입을 위한 Dto입니다 + * @author gengminy 220924 + * */ +@AllArgsConstructor +@NoArgsConstructor +@Getter +@Builder +@ToString +public class MemberDetailResponseDto { + +// private Member member; + //추천인 정보 + private String phone; + + private String name; + + private Gender gender; + + private int age; + + + + private int height; + + private String address; + + private String religion; + + private String drink; + + private String smoke; + + private String mbti; + + private String personality; + + private String introduce; + + private String hobby; + + private String style; + + private String picture; + + private Long point; + + private String school; + + private String major; + + private String eduLevel; + + public static MemberDetailResponseDto of(Member member) { + MemberDetail detail = member.getDetail(); + //회원가입 정보가 없으면 null + if (detail == null) { + return null; + } + return buildDetail(detail); + } + + public static MemberDetailResponseDto of(MemberDetail memberDetail) { + return buildDetail(memberDetail); + } + + private static MemberDetailResponseDto buildDetail(MemberDetail detail) { + return MemberDetailResponseDto.builder() + .height(detail.getHeight()) + .address(detail.getAddress()) + .religion(detail.getReligion()) + .drink(detail.getDrink()) + .smoke(detail.getSmoke()) + .mbti(detail.getMbti()) + .personality(detail.getPersonality()) + .introduce(detail.getIntroduce()) + .hobby(detail.getHobby()) + .style(detail.getStyle()) + .picture(detail.getPicture()) + .point(detail.getPoint()) + .school(detail.getSchool()) + .major(detail.getMajor()) + .eduLevel(detail.getEduLevel()) + .build(); + } + +} diff --git a/src/main/java/com/tikitaka/naechinso/domain/member/entity/Member.java b/src/main/java/com/tikitaka/naechinso/domain/member/entity/Member.java index 02a79e0..2549f6d 100644 --- a/src/main/java/com/tikitaka/naechinso/domain/member/entity/Member.java +++ b/src/main/java/com/tikitaka/naechinso/domain/member/entity/Member.java @@ -85,4 +85,10 @@ public class Member extends BaseEntity { @OneToOne(mappedBy = "receiver") private Recommend recommend_received; + + public void setDetail(MemberDetail memberDetail) { + this.detail = memberDetail; + } + + } diff --git a/src/main/java/com/tikitaka/naechinso/domain/member/entity/MemberDetail.java b/src/main/java/com/tikitaka/naechinso/domain/member/entity/MemberDetail.java index 29cc602..2ec417f 100644 --- a/src/main/java/com/tikitaka/naechinso/domain/member/entity/MemberDetail.java +++ b/src/main/java/com/tikitaka/naechinso/domain/member/entity/MemberDetail.java @@ -1,8 +1,10 @@ package com.tikitaka.naechinso.domain.member.entity; +import com.tikitaka.naechinso.domain.member.dto.MemberDetailJoinRequestDto; import com.tikitaka.naechinso.domain.point.entity.Point; import com.tikitaka.naechinso.global.config.entity.BaseEntity; import com.tikitaka.naechinso.global.config.entity.BaseTimeEntity; +import io.swagger.annotations.ApiModelProperty; import lombok.*; import javax.persistence.*; @@ -70,7 +72,8 @@ public class MemberDetail extends BaseEntity { private String picture; @Column(name = "mem_point") - private Long point; + @Builder.Default + private Long point = 0L; @Column(name = "mem_school") private String school; @@ -91,4 +94,45 @@ public class MemberDetail extends BaseEntity { @MapsId @JoinColumn(name = "mem_id") private Member member; + + + public static MemberDetail of(MemberDetailJoinRequestDto dto) { + return MemberDetail.builder() + .height(dto.getHeight()) + .address(dto.getAddress()) + .religion(dto.getReligion()) + .drink(dto.getDrink()) + .smoke(dto.getSmoke()) + .mbti(dto.getMbti()) + .personality(dto.getPersonality()) + .introduce(dto.getIntroduce()) + .hobby(dto.getHobby()) + .style(dto.getStyle()) + .picture(dto.getPicture()) + .school(dto.getSchool()) + .major(dto.getMajor()) + .eduLevel(dto.getEduLevel()) + .build(); + } + + public static MemberDetail of(Member member, MemberDetailJoinRequestDto dto) { + return MemberDetail.builder() + .height(dto.getHeight()) + .address(dto.getAddress()) + .religion(dto.getReligion()) + .drink(dto.getDrink()) + .smoke(dto.getSmoke()) + .mbti(dto.getMbti()) + .personality(dto.getPersonality()) + .introduce(dto.getIntroduce()) + .hobby(dto.getHobby()) + .style(dto.getStyle()) + .picture(dto.getPicture()) + .school(dto.getSchool()) + .major(dto.getMajor()) + .eduLevel(dto.getEduLevel()) + .member(member) + .build(); + } + } diff --git a/src/main/java/com/tikitaka/naechinso/domain/recommend/RecommendService.java b/src/main/java/com/tikitaka/naechinso/domain/recommend/RecommendService.java index fb33d0a..6310d77 100644 --- a/src/main/java/com/tikitaka/naechinso/domain/recommend/RecommendService.java +++ b/src/main/java/com/tikitaka/naechinso/domain/recommend/RecommendService.java @@ -25,13 +25,25 @@ public RecommendListResponseDTO getRecommendList(Member member) { /** * 추천사를 작성한다 - * @param sender 로그인 여부 및 추천인 정보 가져옴 + * @param member 로그인한 사용자인지 가져옴 * @param dto 추천하려는 사람의 정보 dto * */ public RecommendListResponseDTO recommendMember( - Member sender, + Member member, RecommendRequestDTO dto) { + Member sender; + //작성자가 회원일 경우 그대로 저장 + if (member != null && member.getDetail() != null) { + sender = member; + } + //작성자가 회원이 아닐 경우 + else { + sender = member.builder() + + .build(); + } + //작성자가 회원일 경우, //추천할 사람이 이미 가입하여 요청했을 경우, //둘 모두 회원이 아닐 경우 diff --git a/src/main/java/com/tikitaka/naechinso/domain/recommend/dto/RecommendRequestDTO.java b/src/main/java/com/tikitaka/naechinso/domain/recommend/dto/RecommendRequestDTO.java index 5b5a242..264a202 100644 --- a/src/main/java/com/tikitaka/naechinso/domain/recommend/dto/RecommendRequestDTO.java +++ b/src/main/java/com/tikitaka/naechinso/domain/recommend/dto/RecommendRequestDTO.java @@ -37,4 +37,7 @@ public class RecommendRequestDTO { @NotBlank(message = "친구의 매력을 입력해주세요") private String appeal; + + + } diff --git a/src/main/java/com/tikitaka/naechinso/domain/sms/dto/SmsCertificationRequestDTO.java b/src/main/java/com/tikitaka/naechinso/domain/sms/dto/SmsCertificationRequestDTO.java index 85b983e..7a6db02 100644 --- a/src/main/java/com/tikitaka/naechinso/domain/sms/dto/SmsCertificationRequestDTO.java +++ b/src/main/java/com/tikitaka/naechinso/domain/sms/dto/SmsCertificationRequestDTO.java @@ -1,5 +1,6 @@ package com.tikitaka.naechinso.domain.sms.dto; +import io.swagger.annotations.ApiModelProperty; import lombok.*; import javax.validation.constraints.NotBlank; @@ -13,10 +14,12 @@ @ToString public class SmsCertificationRequestDTO { + @ApiModelProperty(example = "01010001000") @NotBlank(message = "전화번호를 입력해주세요") @Pattern(regexp = "[0-9]{10,11}", message = "하이픈 없는 10~11자리 숫자를 입력해주세요") String phoneNumber; + @ApiModelProperty(example = "000000") @NotBlank(message = "인증번호를 입력해주세요") @Pattern(regexp = "[0-9]{6}", message = "인증번호 6자리를 입력해주세요") String code; diff --git a/src/main/java/com/tikitaka/naechinso/domain/sms/dto/SmsVerificationCodeRequestDTO.java b/src/main/java/com/tikitaka/naechinso/domain/sms/dto/SmsVerificationCodeRequestDTO.java index 99a12bd..af1cb83 100644 --- a/src/main/java/com/tikitaka/naechinso/domain/sms/dto/SmsVerificationCodeRequestDTO.java +++ b/src/main/java/com/tikitaka/naechinso/domain/sms/dto/SmsVerificationCodeRequestDTO.java @@ -1,5 +1,6 @@ package com.tikitaka.naechinso.domain.sms.dto; +import io.swagger.annotations.ApiModelProperty; import lombok.*; import javax.validation.constraints.NotBlank; @@ -11,6 +12,7 @@ @Builder @ToString public class SmsVerificationCodeRequestDTO { + @ApiModelProperty(example = "01010001000") @NotBlank(message = "전화번호를 입력해주세요") @Pattern(regexp = "[0-9]{10,11}", message = "하이픈 없는 10~11자리 숫자를 입력해주세요") String phoneNumber; From 6ddbe49e2f9bbd63808a4685f1e41b02ec02255b Mon Sep 17 00:00:00 2001 From: gengminy Date: Sat, 1 Oct 2022 18:05:53 +0900 Subject: [PATCH 08/72] =?UTF-8?q?:rocket:=20feat(user):=20registerToken=20?= =?UTF-8?q?=EC=B6=94=EA=B0=80=20=EB=B0=8F=20=EC=B6=94=EC=B2=9C=20api=20?= =?UTF-8?q?=EC=84=A4=EA=B3=84=20#20=20#23?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../domain/member/MemberController.java | 36 ++++-- .../dto/MemberDetailJoinRequestDto.java | 8 -- .../member/dto/MemberDetailResponseDto.java | 19 ++- .../domain/member/entity/Member.java | 14 +-- .../domain/member/entity/MemberDetail.java | 3 + .../domain/recommend/RecommendController.java | 67 ++++++++-- .../domain/recommend/RecommendRepository.java | 10 ++ .../domain/recommend/RecommendService.java | 116 ++++++++++++------ .../domain/recommend/dto/RecommendDTO.java | 32 +++-- .../dto/RecommendJoinRequestDTO.java | 112 +++++++++++++++++ .../dto/RecommendListResponseDTO.java | 17 ++- .../recommend/dto/RecommendMetaDTO.java | 18 +++ .../recommend/dto/RecommendRequestDTO.java | 54 +++++--- .../domain/recommend/entity/Recommend.java | 53 ++++++-- .../sms/SmsCertificationController.java | 7 +- .../domain/sms/SmsCertificationService.java | 3 +- .../sms/SmsCertificationServiceImpl.java | 66 +++++----- .../SmsCertificationSuccessResponseDTO.java | 27 ++++ .../common/response/TokenResponseDTO.java | 4 + .../config/security/SecurityConfig.java | 1 + .../config/security/jwt/JwtTokenProvider.java | 14 ++- 21 files changed, 530 insertions(+), 151 deletions(-) create mode 100644 src/main/java/com/tikitaka/naechinso/domain/recommend/dto/RecommendJoinRequestDTO.java create mode 100644 src/main/java/com/tikitaka/naechinso/domain/recommend/dto/RecommendMetaDTO.java create mode 100644 src/main/java/com/tikitaka/naechinso/domain/sms/dto/SmsCertificationSuccessResponseDTO.java diff --git a/src/main/java/com/tikitaka/naechinso/domain/member/MemberController.java b/src/main/java/com/tikitaka/naechinso/domain/member/MemberController.java index fdebfa5..1ce3835 100644 --- a/src/main/java/com/tikitaka/naechinso/domain/member/MemberController.java +++ b/src/main/java/com/tikitaka/naechinso/domain/member/MemberController.java @@ -7,11 +7,14 @@ import com.tikitaka.naechinso.domain.member.entity.Member; import com.tikitaka.naechinso.global.annotation.AuthMember; import com.tikitaka.naechinso.global.config.CommonApiResponse; +import com.tikitaka.naechinso.global.config.security.jwt.JwtTokenProvider; import com.tikitaka.naechinso.global.error.ErrorCode; import com.tikitaka.naechinso.global.error.exception.UnauthorizedException; +import io.jsonwebtoken.Claims; import io.swagger.annotations.ApiOperation; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; +import org.apache.commons.lang3.StringUtils; import org.springframework.web.bind.annotation.*; import springfox.documentation.annotations.ApiIgnore; @@ -26,6 +29,7 @@ public class MemberController { private final MemberService memberService; + private final JwtTokenProvider jwtTokenService; @GetMapping("/") @ApiOperation(value = "유저 자신의 모든 정보를 가져온다 (AccessToken 필요)") @@ -38,14 +42,20 @@ public CommonApiResponse getMyInformation( return CommonApiResponse.of(MemberCommonResponseDto.of(member)); } - @PostMapping("/join") - @ApiOperation(value = "공통 유저를 기본 정보로 회원가입 시킨다") - public CommonApiResponse joinCommonMember( - @Valid @RequestBody MemberCommonJoinRequestDto dto) - { - final MemberCommonResponseDto res = memberService.createCommonMember(dto); - return CommonApiResponse.of(res); - } +// @PostMapping("/join") +// @ApiOperation(value = "공통 유저를 기본 정보로 회원가입 시킨다 (registerToken 필요)") +// public CommonApiResponse joinCommonMember( +// HttpServletRequest request, +// @Valid @RequestBody MemberCommonJoinRequestDto dto) +// { +// String registerToken = request.getHeader("Authorization"); +// if (StringUtils.isBlank(registerToken) || !jwtTokenService.validateToken(registerToken)) { +// throw new UnauthorizedException(ErrorCode.NO_TOKEN); +// } +// +// final MemberCommonResponseDto res = memberService.createCommonMember(dto); +// return CommonApiResponse.of(res); +// } @GetMapping("/detail") @ApiOperation(value = "회원가입 세부 정보를 가져온다 (AccessToken 필요)") @@ -60,8 +70,8 @@ public CommonApiResponse getMemberDetail( return CommonApiResponse.of(res); } - @PostMapping("/detail") - @ApiOperation(value = "회원가입 세부 정보를 입력한다 (AccessToken 필요)") + @PostMapping("/join") + @ApiOperation(value = "회원가입 세부 정보를 입력하여 최종 가입시킨다 (AccessToken 필요)") public CommonApiResponse setMemberDetail( @Valid @RequestBody MemberDetailJoinRequestDto dto, @ApiIgnore @AuthMember Member member) @@ -81,6 +91,12 @@ public CommonApiResponse> getMyInformation() { return CommonApiResponse.of(memberService.findAll()); } + @PostMapping("/recommend") + @ApiOperation(value = "다른 유저의 추천사를 작성한다") + public CommonApiResponse createRecommend() { + return CommonApiResponse.of(null); + } + // @PostMapping("/login") diff --git a/src/main/java/com/tikitaka/naechinso/domain/member/dto/MemberDetailJoinRequestDto.java b/src/main/java/com/tikitaka/naechinso/domain/member/dto/MemberDetailJoinRequestDto.java index ade8873..8d162c0 100644 --- a/src/main/java/com/tikitaka/naechinso/domain/member/dto/MemberDetailJoinRequestDto.java +++ b/src/main/java/com/tikitaka/naechinso/domain/member/dto/MemberDetailJoinRequestDto.java @@ -66,12 +66,4 @@ public class MemberDetailJoinRequestDto { @ApiModelProperty(example = "대학교") private String eduLevel; - - public static Member toCommonMember(MemberDetailJoinRequestDto dto) { - Member member = Member.builder() - - .build(); - - return member; - } } diff --git a/src/main/java/com/tikitaka/naechinso/domain/member/dto/MemberDetailResponseDto.java b/src/main/java/com/tikitaka/naechinso/domain/member/dto/MemberDetailResponseDto.java index 193610a..2a0b5ea 100644 --- a/src/main/java/com/tikitaka/naechinso/domain/member/dto/MemberDetailResponseDto.java +++ b/src/main/java/com/tikitaka/naechinso/domain/member/dto/MemberDetailResponseDto.java @@ -3,6 +3,8 @@ import com.tikitaka.naechinso.domain.member.constant.Gender; import com.tikitaka.naechinso.domain.member.entity.Member; import com.tikitaka.naechinso.domain.member.entity.MemberDetail; +import com.tikitaka.naechinso.global.error.ErrorCode; +import com.tikitaka.naechinso.global.error.exception.NotFoundException; import lombok.*; import javax.persistence.Column; @@ -76,7 +78,22 @@ public static MemberDetailResponseDto of(MemberDetail memberDetail) { } private static MemberDetailResponseDto buildDetail(MemberDetail detail) { - return MemberDetailResponseDto.builder() + MemberDetailResponseDtoBuilder dtoBuilder = MemberDetailResponseDto.builder(); + Member member = detail.getMember(); + + //멤버 정보가 연결되어 있으면 가져옴 + if (member != null) { + dtoBuilder.phone(member.getPhone()) + .name(member.getName()) + .gender(member.getGender()) + .age(member.getAge()); + + } else { + //없으면 에러 + throw new NotFoundException(ErrorCode.USER_NOT_FOUND); + } + + return dtoBuilder .height(detail.getHeight()) .address(detail.getAddress()) .religion(detail.getReligion()) diff --git a/src/main/java/com/tikitaka/naechinso/domain/member/entity/Member.java b/src/main/java/com/tikitaka/naechinso/domain/member/entity/Member.java index 2549f6d..e92cabc 100644 --- a/src/main/java/com/tikitaka/naechinso/domain/member/entity/Member.java +++ b/src/main/java/com/tikitaka/naechinso/domain/member/entity/Member.java @@ -1,7 +1,7 @@ package com.tikitaka.naechinso.domain.member.entity; +import com.fasterxml.jackson.annotation.JsonIgnore; import com.tikitaka.naechinso.domain.member.constant.Gender; -import com.tikitaka.naechinso.domain.point.entity.Point; import com.tikitaka.naechinso.domain.recommend.entity.Recommend; import com.tikitaka.naechinso.global.config.entity.BaseEntity; import lombok.*; @@ -76,19 +76,19 @@ public class Member extends BaseEntity { @JoinColumn(name = "mem_detail") private MemberDetail detail; - //소개해준 사람들 -> recommend 로 넣으면 됨 + //내가 소개해준 사람들 //mapped by 에는 연관관계 엔티티의 필드명을 적어줌 @OneToMany(mappedBy = "sender") + @JsonIgnore private List recommends = new ArrayList<>(); - //소개해준 사람들 -> recommend 로 넣으면 됨 - @OneToOne(mappedBy = "receiver") - private Recommend recommend_received; + //나를 소개해준 사람들 + @OneToMany(mappedBy = "receiver") + @JsonIgnore //순환참조 방지, 엔티티 프로퍼티 가려줌 + private List recommend_received = new ArrayList<>(); public void setDetail(MemberDetail memberDetail) { this.detail = memberDetail; } - - } diff --git a/src/main/java/com/tikitaka/naechinso/domain/member/entity/MemberDetail.java b/src/main/java/com/tikitaka/naechinso/domain/member/entity/MemberDetail.java index 2ec417f..bdfe570 100644 --- a/src/main/java/com/tikitaka/naechinso/domain/member/entity/MemberDetail.java +++ b/src/main/java/com/tikitaka/naechinso/domain/member/entity/MemberDetail.java @@ -1,5 +1,6 @@ package com.tikitaka.naechinso.domain.member.entity; +import com.fasterxml.jackson.annotation.JsonIgnore; import com.tikitaka.naechinso.domain.member.dto.MemberDetailJoinRequestDto; import com.tikitaka.naechinso.domain.point.entity.Point; import com.tikitaka.naechinso.global.config.entity.BaseEntity; @@ -88,11 +89,13 @@ public class MemberDetail extends BaseEntity { @OneToMany(mappedBy = "member") private List points = new ArrayList<>(); + // MemberDetail 을 소유한 Member 와 연결 // Member Entity 와 1:1 조인 // Member PK 그대로 사용 @OneToOne(cascade = CascadeType.ALL, fetch = FetchType.LAZY) @MapsId @JoinColumn(name = "mem_id") + @JsonIgnore private Member member; diff --git a/src/main/java/com/tikitaka/naechinso/domain/recommend/RecommendController.java b/src/main/java/com/tikitaka/naechinso/domain/recommend/RecommendController.java index eae4116..39645b9 100644 --- a/src/main/java/com/tikitaka/naechinso/domain/recommend/RecommendController.java +++ b/src/main/java/com/tikitaka/naechinso/domain/recommend/RecommendController.java @@ -1,21 +1,24 @@ package com.tikitaka.naechinso.domain.recommend; -import com.tikitaka.naechinso.domain.member.dto.MemberCommonResponseDto; import com.tikitaka.naechinso.domain.member.entity.Member; +import com.tikitaka.naechinso.domain.recommend.dto.RecommendDTO; +import com.tikitaka.naechinso.domain.recommend.dto.RecommendJoinRequestDTO; import com.tikitaka.naechinso.domain.recommend.dto.RecommendListResponseDTO; import com.tikitaka.naechinso.domain.recommend.dto.RecommendRequestDTO; import com.tikitaka.naechinso.global.annotation.AuthMember; import com.tikitaka.naechinso.global.config.CommonApiResponse; +import com.tikitaka.naechinso.global.config.security.jwt.JwtTokenProvider; import com.tikitaka.naechinso.global.error.ErrorCode; import com.tikitaka.naechinso.global.error.exception.UnauthorizedException; import io.swagger.annotations.ApiOperation; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; -import org.springframework.stereotype.Controller; +import org.apache.commons.lang3.StringUtils; import org.springframework.web.bind.annotation.*; import springfox.documentation.annotations.ApiIgnore; import javax.servlet.http.HttpServletRequest; +import javax.validation.Valid; @Slf4j @RestController @@ -24,29 +27,71 @@ public class RecommendController { private final RecommendService recommendService; + private final JwtTokenProvider jwtTokenService; @GetMapping("/") @ApiOperation(value = "내 추천사 정보를 가져온다 (AccessToken 필요)") public CommonApiResponse getRecommends( - HttpServletRequest request, @ApiIgnore @AuthMember Member member) { if (member == null) { throw new UnauthorizedException(ErrorCode.UNAUTHORIZED_USER); } - return CommonApiResponse.of(recommendService.getRecommendList(member)); + return CommonApiResponse.of(recommendService.readRecommendList(member)); } @PostMapping("/") - @ApiOperation(value = "추천사를 작성한다 (AccessToken 필요)") - public CommonApiResponse writeRecommend( + @ApiOperation(value = "추천서를 작성한 후, 추천인을 회원가입 시킨다. (registerToken 필요)") + public CommonApiResponse createRecommendNewSender( HttpServletRequest request, - @RequestBody RecommendRequestDTO dto, - @ApiIgnore @AuthMember Member member) + @Valid @RequestBody RecommendJoinRequestDTO dto) { - if (member == null) { - throw new UnauthorizedException(ErrorCode.UNAUTHORIZED_USER); + String registerToken = request.getHeader("Authorization"); + String phone = parseRegisterToken(registerToken); + + RecommendDTO recommendDTO = recommendService.createRecommendJoin(phone, dto); + return CommonApiResponse.of(recommendDTO); + } + + @PostMapping("/request") + @ApiOperation(value = "다른 유저에게 추천서 작성을 요청한다 (registerToken 필요)") + public CommonApiResponse createRecommendRequest( + HttpServletRequest request, + @Valid @RequestBody RecommendRequestDTO dto) + { + String registerToken = request.getHeader("Authorization"); + String phone = parseRegisterToken(registerToken); + RecommendDTO recommendDTO = recommendService.createRecommendRequest(phone, dto); + return CommonApiResponse.of(recommendDTO); + } + + + + + + + + +// //제일 아래에 있어야함 +// @GetMapping("/{uuid}") +// @ApiOperation(value = "추천 요청 uuid 를 가진 추천사 엔티티를 가져온다") +// public CommonApiResponse getRecommendByUuid( +// HttpServletRequest request, +// @PathVariable("uuid") String uuid, +// @Valid @RequestBody RecommendRequestDTO dto) +// { +// String registerToken = request.getHeader("Authorization"); +// String phone = parseRegisterToken(registerToken); +// +//// RecommendDTO recommendDTO = recommendService.findAllRecommendRequestsByUuid(uuid); +// return CommonApiResponse.of(recommendDTO); +// } + + private String parseRegisterToken(String registerToken) { + if (StringUtils.isBlank(registerToken) || !jwtTokenService.validateToken(registerToken)) { + throw new UnauthorizedException(ErrorCode.NO_TOKEN); } - return CommonApiResponse.of(MemberCommonResponseDto.of(member)); + return jwtTokenService.parseClaims(registerToken).getSubject(); } + } diff --git a/src/main/java/com/tikitaka/naechinso/domain/recommend/RecommendRepository.java b/src/main/java/com/tikitaka/naechinso/domain/recommend/RecommendRepository.java index 5bb4fb8..da597a8 100644 --- a/src/main/java/com/tikitaka/naechinso/domain/recommend/RecommendRepository.java +++ b/src/main/java/com/tikitaka/naechinso/domain/recommend/RecommendRepository.java @@ -1,10 +1,20 @@ package com.tikitaka.naechinso.domain.recommend; +import com.tikitaka.naechinso.domain.member.entity.Member; import com.tikitaka.naechinso.domain.member.entity.MemberDetail; import com.tikitaka.naechinso.domain.recommend.entity.Recommend; import org.springframework.data.jpa.repository.JpaRepository; import org.springframework.stereotype.Repository; +import java.util.List; +import java.util.Optional; + @Repository public interface RecommendRepository extends JpaRepository { + List findAllByReceiver_Id(Long id); + List findAllByReceiverPhone(String phone); + List findAllBySender_Id(Long id); + List findAllBySenderPhone(String phone); + + Boolean existsByReceiverPhone(String phone); } diff --git a/src/main/java/com/tikitaka/naechinso/domain/recommend/RecommendService.java b/src/main/java/com/tikitaka/naechinso/domain/recommend/RecommendService.java index 6310d77..67c80f3 100644 --- a/src/main/java/com/tikitaka/naechinso/domain/recommend/RecommendService.java +++ b/src/main/java/com/tikitaka/naechinso/domain/recommend/RecommendService.java @@ -2,13 +2,20 @@ import com.tikitaka.naechinso.domain.member.MemberRepository; import com.tikitaka.naechinso.domain.member.entity.Member; +import com.tikitaka.naechinso.domain.recommend.dto.RecommendDTO; +import com.tikitaka.naechinso.domain.recommend.dto.RecommendJoinRequestDTO; import com.tikitaka.naechinso.domain.recommend.dto.RecommendListResponseDTO; import com.tikitaka.naechinso.domain.recommend.dto.RecommendRequestDTO; import com.tikitaka.naechinso.domain.recommend.entity.Recommend; +import com.tikitaka.naechinso.global.error.ErrorCode; +import com.tikitaka.naechinso.global.error.exception.BadRequestException; +import com.tikitaka.naechinso.global.error.exception.NotFoundException; import lombok.RequiredArgsConstructor; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; +import java.util.ArrayList; +import java.util.List; import java.util.Optional; @Service @@ -19,52 +26,83 @@ public class RecommendService { private final RecommendRepository recommendRepository; private final MemberRepository memberRepository; - public RecommendListResponseDTO getRecommendList(Member member) { + public RecommendListResponseDTO readRecommendList(Member authMember) { + Member member = memberRepository.findByPhone(authMember.getPhone()) + .orElseThrow(() -> new NotFoundException(ErrorCode.USER_NOT_FOUND)); return RecommendListResponseDTO.of(member); } - /** - * 추천사를 작성한다 - * @param member 로그인한 사용자인지 가져옴 - * @param dto 추천하려는 사람의 정보 dto - * */ - public RecommendListResponseDTO recommendMember( - Member member, - RecommendRequestDTO dto) - { - Member sender; - //작성자가 회원일 경우 그대로 저장 - if (member != null && member.getDetail() != null) { - sender = member; - } - //작성자가 회원이 아닐 경우 - else { - sender = member.builder() + public RecommendDTO createRecommendJoin(String senderPhone, RecommendJoinRequestDTO dto) { + //멤버가 이미 있으면 종료 + Optional checkSender = memberRepository.findByPhone(senderPhone); + if (checkSender.isPresent()) { + throw new BadRequestException(ErrorCode.USER_ALREADY_EXIST); + } + Member sender = dto.toSender(senderPhone); + + Member receiver = memberRepository.findByPhone(dto.getReceiverPhone()) + .orElse(null); + + Recommend recommend = Recommend.builder() + .sender(sender) + .senderPhone(senderPhone) + .senderName(dto.getName()) + .senderAge(dto.getAge()) + .senderGender(dto.getGender()) + .senderJobName(dto.getJobName()) + .senderJobPart(dto.getJobPart()) + .senderJobLocation(dto.getJobLocation()) + .receiver(receiver) + .receiverPhone(dto.getReceiverPhone()) + .receiverName(dto.getReceiverName()) + .receiverAge(dto.getReceiverAge()) + .receiverAppeal(dto.getAppeal()) + .receiverGender(dto.getReceiverGender()) + .receiverMeet(dto.getMeet()) + .receiverPersonality(dto.getPersonality()) .build(); - } - - //작성자가 회원일 경우, - //추천할 사람이 이미 가입하여 요청했을 경우, - //둘 모두 회원이 아닐 경우 - - Optional checkMember = memberRepository.findByPhone(dto.getPhone()); - Member receiver; - //상대가 이미 있는 유저면 FK 로 저장 - if (checkMember.isPresent()) { - receiver = checkMember.get(); - } - //상대가 없는 유저면 새로 만든 후 FK 저장 - else { - receiver = Member.builder() - .build(); - } - Recommend recommend = Recommend.builder() - .sender(sender) - .phone(receiver.getPhone()) + memberRepository.save(sender); + recommendRepository.save(recommend); + return RecommendDTO.of(recommend); + } + + public RecommendDTO createRecommendRequest(String receiverPhone, RecommendRequestDTO dto) { + Member receiver = dto.toReceiver(receiverPhone); + Recommend recommend = Recommend.builder() + .sender(null) + .receiver(receiver) + .receiverPhone(receiverPhone) + .receiverName(dto.getName()) + .receiverAge(dto.getAge()) + .receiverGender(dto.getGender()) .build(); - return RecommendListResponseDTO.of(receiver); + + memberRepository.save(receiver); + recommendRepository.save(recommend); + + return RecommendDTO.of(recommend); + } + + public List findAllBySenderPhone(String phone) { + List recommendDTOList = new ArrayList<>(); + recommendRepository.findAllBySenderPhone(phone).stream().map( + recommend -> recommendDTOList.add(RecommendDTO.of(recommend)) + ); + return recommendDTOList; } + +// //링크로 요청한 +// public RecommendDTO findAllRecommendRequestsByUuid(String uuid){ +// RecommendMeta meta = recommendMetaRepository.findByUuid(uuid) +// .orElseThrow(() -> new NotFoundException(ErrorCode.USER_NOT_FOUND)); +// return RecommendDTO.of(meta.getRecommend()); +// } + + public Boolean existsByReceiverPhone(String phone){ + return recommendRepository.existsByReceiverPhone(phone); + } + } diff --git a/src/main/java/com/tikitaka/naechinso/domain/recommend/dto/RecommendDTO.java b/src/main/java/com/tikitaka/naechinso/domain/recommend/dto/RecommendDTO.java index 2bf4c39..573b7da 100644 --- a/src/main/java/com/tikitaka/naechinso/domain/recommend/dto/RecommendDTO.java +++ b/src/main/java/com/tikitaka/naechinso/domain/recommend/dto/RecommendDTO.java @@ -16,9 +16,9 @@ public class RecommendDTO { private String phone; - private Member sender; + private Long senderId; - private Member receiver; + private Long receiverId; private String name; @@ -30,14 +30,28 @@ public class RecommendDTO { public static RecommendDTO of(Recommend recommend) { + Long senderId; + Long receiverId; + if (recommend.getSender() == null) { + senderId = null; + } else { + senderId = recommend.getSender().getId(); + } + + if (recommend.getReceiver() == null) { + receiverId = null; + } else { + receiverId = recommend.getReceiver().getId(); + } + return RecommendDTO.builder() - .phone(recommend.getPhone()) - .sender(recommend.getSender()) - .receiver(recommend.getReceiver()) - .name(recommend.getName()) - .gender(recommend.getGender()) - .meet(recommend.getMeet()) - .appeal(recommend.getAppeal()) + .phone(recommend.getReceiverPhone()) + .senderId(senderId) + .receiverId(receiverId) + .name(recommend.getReceiverName()) + .gender(recommend.getReceiverGender()) + .meet(recommend.getReceiverMeet()) + .appeal(recommend.getReceiverAppeal()) .build(); } } diff --git a/src/main/java/com/tikitaka/naechinso/domain/recommend/dto/RecommendJoinRequestDTO.java b/src/main/java/com/tikitaka/naechinso/domain/recommend/dto/RecommendJoinRequestDTO.java new file mode 100644 index 0000000..50a1c9c --- /dev/null +++ b/src/main/java/com/tikitaka/naechinso/domain/recommend/dto/RecommendJoinRequestDTO.java @@ -0,0 +1,112 @@ +package com.tikitaka.naechinso.domain.recommend.dto; + +import com.tikitaka.naechinso.domain.member.constant.Gender; +import com.tikitaka.naechinso.domain.member.entity.Member; +import com.tikitaka.naechinso.global.annotation.Enum; +import io.swagger.annotations.ApiModelProperty; +import lombok.*; + +import javax.validation.constraints.*; + +/** 가입하지 않은 멤버가 추천사를 써줄 때 요청 DTO + * @author gengminy 221001 +*/ +@AllArgsConstructor +@NoArgsConstructor +@Getter +@Builder +@ToString +public class RecommendJoinRequestDTO { + @ApiModelProperty(example = "닉") + @NotBlank(message = "이름을 입력해주세요") + private String name; + + @ApiModelProperty(example = "M") + @Enum(enumClass = Gender.class, message = "성별 입력이 올바르지 않습니다. M 또는 W가 필요합니다") + private Gender gender; + + @ApiModelProperty(example = "25") + @Min(value = 25, message = "25-33세까지만 가입 가능합니다") + @Max(value = 33, message = "25-33세까지만 가입 가능합니다") + private int age; + + @NotNull(message = "서비스 이용약관 동의가 필요합니다") + @AssertTrue(message = "서비스 이용약관 동의가 필요합니다") + private boolean acceptsService; + + @NotNull(message = "개인정보 이용 동의가 필요합니다") + @AssertTrue(message = "개인정보 이용 동의가 필요합니다") + private boolean acceptsInfo; + + @NotNull(message = "종교 정보 제공 동의가 필요합니다") + @AssertTrue(message = "종교 정보 제공 동의가 필요합니다") + private boolean acceptsReligion; + + @NotNull(message = "위치 정보 제공 동의 여부가 필요합니다") + private boolean acceptsLocation; + + @NotNull(message = "마케팅 동의 여부가 필요합니다") + private boolean acceptsMarketing; + + @ApiModelProperty(example = "카카오") + @NotBlank(message = "직장명을 입력해주세요") + private String jobName; + + @ApiModelProperty(example = "개발자") + @NotBlank(message = "직장 부서를 입력해주세요") + private String jobPart; + + @ApiModelProperty(example = "판교") + @NotBlank(message = "직장 위치를 입력해주세요") + private String jobLocation; + + + + @ApiModelProperty(example = "01099999999") + @NotBlank(message = "친구의 전화번호를 입력해주세요") + @Pattern(regexp = "[0-9]{10,11}", message = "하이픈 없는 10~11자리 숫자를 입력해주세요") + private String receiverPhone; + + @ApiModelProperty(example = "박스") + @NotBlank(message = "친구의 이름을 입력해주세요") + private String receiverName; + + @ApiModelProperty(example = "M") + @Enum(enumClass = Gender.class, message = "친구의 성별 입력이 올바르지 않습니다. M 또는 W가 필요합니다") + private Gender receiverGender; + + @ApiModelProperty(example = "25") + @Min(value = 25, message = "25-33세까지만 추천 및 가입 가능합니다") + @Max(value = 33, message = "25-33세까지만 추천 및 가입 가능합니다") + private int receiverAge; + + @ApiModelProperty(example = "CMC 에서") + @NotBlank(message = "만나게 된 계기를 입력해주세요") + private String meet; + + @ApiModelProperty(example = "최고") + @NotBlank(message = "친구의 성격 키워드를 입력해주세요") + private String personality; + + @ApiModelProperty(example = "짱") + @NotBlank(message = "친구의 매력을 입력해주세요") + private String appeal; + + + public Member toSender(String phone){ + return Member.builder() + .phone(phone) + .name(this.name) + .gender(this.gender) + .age(this.age) + .acceptsService(this.acceptsService) + .acceptsInfo(this.acceptsInfo) + .acceptsReligion(this.acceptsReligion) + .acceptsLocation(this.acceptsLocation) + .acceptsMarketing(this.acceptsMarketing) + .jobName(this.jobName) + .jobPart(this.jobPart) + .jobLocation(this.jobLocation) + .build(); + } +} diff --git a/src/main/java/com/tikitaka/naechinso/domain/recommend/dto/RecommendListResponseDTO.java b/src/main/java/com/tikitaka/naechinso/domain/recommend/dto/RecommendListResponseDTO.java index 609c920..ff98099 100644 --- a/src/main/java/com/tikitaka/naechinso/domain/recommend/dto/RecommendListResponseDTO.java +++ b/src/main/java/com/tikitaka/naechinso/domain/recommend/dto/RecommendListResponseDTO.java @@ -13,18 +13,27 @@ @Builder @ToString public class RecommendListResponseDTO { - List recommends = new ArrayList<>(); + List recommend = new ArrayList<>(); + List recommendReceived = new ArrayList<>(); public static RecommendListResponseDTO of(Member member) { - List recommendDTOList = new ArrayList<>(); + List recommendList = new ArrayList<>(); + List recommendReceivedList = new ArrayList<>(); member.getRecommends().stream().forEach(recommend -> - recommendDTOList.add(RecommendDTO.of(recommend)) + recommendList.add(RecommendDTO.of(recommend)) + ); + + member.getRecommend_received().stream().forEach(recommend -> + recommendReceivedList.add(RecommendDTO.of(recommend)) ); return RecommendListResponseDTO.builder() - .recommends(recommendDTOList) + .recommend(recommendList) + .recommendReceived(recommendReceivedList) .build(); } + + } diff --git a/src/main/java/com/tikitaka/naechinso/domain/recommend/dto/RecommendMetaDTO.java b/src/main/java/com/tikitaka/naechinso/domain/recommend/dto/RecommendMetaDTO.java new file mode 100644 index 0000000..69c16df --- /dev/null +++ b/src/main/java/com/tikitaka/naechinso/domain/recommend/dto/RecommendMetaDTO.java @@ -0,0 +1,18 @@ +package com.tikitaka.naechinso.domain.recommend.dto; + +import com.tikitaka.naechinso.domain.member.constant.Gender; +import com.tikitaka.naechinso.domain.recommend.entity.Recommend; +import lombok.*; + +import java.util.UUID; + +@AllArgsConstructor +@NoArgsConstructor +@Getter +@Builder +@ToString +public class RecommendMetaDTO { + private UUID uuid; + + private Recommend recommend; +} diff --git a/src/main/java/com/tikitaka/naechinso/domain/recommend/dto/RecommendRequestDTO.java b/src/main/java/com/tikitaka/naechinso/domain/recommend/dto/RecommendRequestDTO.java index 264a202..eced9bf 100644 --- a/src/main/java/com/tikitaka/naechinso/domain/recommend/dto/RecommendRequestDTO.java +++ b/src/main/java/com/tikitaka/naechinso/domain/recommend/dto/RecommendRequestDTO.java @@ -1,13 +1,14 @@ package com.tikitaka.naechinso.domain.recommend.dto; import com.tikitaka.naechinso.domain.member.constant.Gender; +import com.tikitaka.naechinso.domain.member.entity.Member; import com.tikitaka.naechinso.global.annotation.Enum; import lombok.*; -import javax.validation.constraints.Max; -import javax.validation.constraints.Min; -import javax.validation.constraints.NotBlank; -import javax.validation.constraints.Pattern; +import javax.persistence.Column; +import javax.persistence.GeneratedValue; +import javax.validation.constraints.*; +import java.util.UUID; @AllArgsConstructor @NoArgsConstructor @@ -15,29 +16,50 @@ @Builder @ToString public class RecommendRequestDTO { - @NotBlank(message = "친구의 전화번호를 입력해주세요") - @Pattern(regexp = "[0-9]{10,11}", message = "하이픈 없는 10~11자리 숫자를 입력해주세요") - private String phone; - - @NotBlank(message = "친구의 이름을 입력해주세요") + @NotBlank(message = "유저 이름을 입력해주세요") private String name; - @Enum(enumClass = Gender.class, message = "친구의 성별 입력이 올바르지 않습니다. M 또는 W가 필요합니다") + @Enum(enumClass = Gender.class, message = "유저의 성별 입력이 올바르지 않습니다. M 또는 W가 필요합니다") private Gender gender; @Min(value = 25, message = "25-33세까지만 추천 및 가입 가능합니다") @Max(value = 33, message = "25-33세까지만 추천 및 가입 가능합니다") private int age; - @NotBlank(message = "만나게 된 계기를 입력해주세요") - private String meet; + @NotNull(message = "서비스 이용약관 동의가 필요합니다") + @AssertTrue(message = "서비스 이용약관 동의가 필요합니다") + private boolean acceptsService; + + @NotNull(message = "개인정보 이용 동의가 필요합니다") + @AssertTrue(message = "개인정보 이용 동의가 필요합니다") + private boolean acceptsInfo; + + @NotNull(message = "종교 정보 제공 동의가 필요합니다") + @AssertTrue(message = "종교 정보 제공 동의가 필요합니다") + private boolean acceptsReligion; - @NotBlank(message = "친구의 성격 키워드를 입력해주세요") - private String personality; + @NotNull(message = "위치 정보 제공 동의 여부가 필요합니다") + private boolean acceptsLocation; - @NotBlank(message = "친구의 매력을 입력해주세요") - private String appeal; + @NotNull(message = "마케팅 동의 여부가 필요합니다") + private boolean acceptsMarketing; + //링크 식별을 위한 uuid + @Builder.Default + private String uuid = UUID.randomUUID().toString(); + public Member toReceiver(String phone) { + return Member.builder() + .name(this.getName()) + .name(this.name) + .gender(this.gender) + .age(this.age) + .acceptsService(this.acceptsService) + .acceptsInfo(this.acceptsInfo) + .acceptsReligion(this.acceptsReligion) + .acceptsLocation(this.acceptsLocation) + .acceptsMarketing(this.acceptsMarketing) + .build(); + } } diff --git a/src/main/java/com/tikitaka/naechinso/domain/recommend/entity/Recommend.java b/src/main/java/com/tikitaka/naechinso/domain/recommend/entity/Recommend.java index dee7999..906512f 100644 --- a/src/main/java/com/tikitaka/naechinso/domain/recommend/entity/Recommend.java +++ b/src/main/java/com/tikitaka/naechinso/domain/recommend/entity/Recommend.java @@ -1,9 +1,10 @@ package com.tikitaka.naechinso.domain.recommend.entity; +import com.fasterxml.jackson.annotation.JsonIgnore; import com.tikitaka.naechinso.domain.member.constant.Gender; import com.tikitaka.naechinso.domain.member.entity.Member; +import com.tikitaka.naechinso.domain.recommend.dto.RecommendJoinRequestDTO; import com.tikitaka.naechinso.global.config.entity.BaseEntity; -import com.tikitaka.naechinso.global.config.entity.BaseTimeEntity; import lombok.*; import javax.persistence.*; @@ -26,28 +27,64 @@ public class Recommend extends BaseEntity { @Column(name = "rec_id") private Long id; + /* 추천 해준 사람 */ @ManyToOne(fetch = FetchType.LAZY) @JoinColumn(name = "mem_id") + @JsonIgnore private Member sender; + @Column(name = "mem_phone") + private String senderPhone; + + @Column(name = "mem_name") + private String senderName; + + @Column(name = "mem_gender") + private Gender senderGender; + + @Column(name = "mem_age") + private int senderAge; + + @Column(name = "mem_job_name") + private String senderJobName; + + @Column(name = "mem_job_part") + private String senderJobPart; + + @Column(name = "mem_job_location") + private String senderJobLocation; + /* 받는 사람이 아직 가입 안했으면 NULL 일수도 있음 */ - @OneToOne + @ManyToOne(fetch = FetchType.LAZY) + @JsonIgnore @JoinColumn(name = "rec_target_id") private Member receiver; + @Column(name = "rec_phone") + private String receiverPhone; + @Column(name = "rec_name") - private String name; + private String receiverName; @Column(name = "rec_gender") @Enumerated(EnumType.STRING) - private Gender gender; + private Gender receiverGender; + + @Column(name = "rec_age") + private int receiverAge; @Column(name = "rec_meet") - private String meet; + private String receiverMeet; + + @Column(name = "rec_personality") + private String receiverPersonality; @Column(name = "rec_appeal") - private String appeal; + private String receiverAppeal; + + public static Recommend of(RecommendJoinRequestDTO dto) { + return Recommend.builder() + .build(); + } - @Column(name = "rec_phone") - private String phone; } diff --git a/src/main/java/com/tikitaka/naechinso/domain/sms/SmsCertificationController.java b/src/main/java/com/tikitaka/naechinso/domain/sms/SmsCertificationController.java index b3dab7b..7989d8a 100644 --- a/src/main/java/com/tikitaka/naechinso/domain/sms/SmsCertificationController.java +++ b/src/main/java/com/tikitaka/naechinso/domain/sms/SmsCertificationController.java @@ -1,5 +1,6 @@ package com.tikitaka.naechinso.domain.sms; +import com.tikitaka.naechinso.domain.sms.dto.SmsCertificationSuccessResponseDTO; import com.tikitaka.naechinso.global.common.response.TokenResponseDTO; import com.tikitaka.naechinso.global.config.CommonApiResponse; import com.tikitaka.naechinso.domain.sms.dto.SmsCertificationRequestDTO; @@ -27,8 +28,8 @@ public CommonApiResponse sendMessageWithVerificationCode(@Valid @Reques } @PostMapping("/verify") - public CommonApiResponse verifyCode(@RequestBody @Valid SmsCertificationRequestDTO dto) { - TokenResponseDTO token = smsCertificationService.verifyCode(dto); - return CommonApiResponse.of(token); + public CommonApiResponse verifyCode(@RequestBody @Valid SmsCertificationRequestDTO dto) { + SmsCertificationSuccessResponseDTO responseDTO = smsCertificationService.verifyCode(dto); + return CommonApiResponse.of(responseDTO); } } diff --git a/src/main/java/com/tikitaka/naechinso/domain/sms/SmsCertificationService.java b/src/main/java/com/tikitaka/naechinso/domain/sms/SmsCertificationService.java index af92542..93f1353 100644 --- a/src/main/java/com/tikitaka/naechinso/domain/sms/SmsCertificationService.java +++ b/src/main/java/com/tikitaka/naechinso/domain/sms/SmsCertificationService.java @@ -1,11 +1,12 @@ package com.tikitaka.naechinso.domain.sms; import com.tikitaka.naechinso.domain.sms.dto.SmsCertificationRequestDTO; +import com.tikitaka.naechinso.domain.sms.dto.SmsCertificationSuccessResponseDTO; import com.tikitaka.naechinso.global.common.response.TokenResponseDTO; import org.springframework.stereotype.Service; @Service public interface SmsCertificationService { String sendVerificationMessage(String to); - TokenResponseDTO verifyCode(SmsCertificationRequestDTO smsCertificationRequestDto); + SmsCertificationSuccessResponseDTO verifyCode(SmsCertificationRequestDTO smsCertificationRequestDto); } diff --git a/src/main/java/com/tikitaka/naechinso/domain/sms/SmsCertificationServiceImpl.java b/src/main/java/com/tikitaka/naechinso/domain/sms/SmsCertificationServiceImpl.java index 1f47e92..330009a 100644 --- a/src/main/java/com/tikitaka/naechinso/domain/sms/SmsCertificationServiceImpl.java +++ b/src/main/java/com/tikitaka/naechinso/domain/sms/SmsCertificationServiceImpl.java @@ -4,6 +4,11 @@ import com.tikitaka.naechinso.domain.member.MemberRepository; import com.tikitaka.naechinso.domain.member.MemberService; import com.tikitaka.naechinso.domain.member.entity.Member; +import com.tikitaka.naechinso.domain.recommend.RecommendRepository; +import com.tikitaka.naechinso.domain.recommend.RecommendService; +import com.tikitaka.naechinso.domain.recommend.dto.RecommendDTO; +import com.tikitaka.naechinso.domain.recommend.dto.RecommendListResponseDTO; +import com.tikitaka.naechinso.domain.sms.dto.SmsCertificationSuccessResponseDTO; import com.tikitaka.naechinso.global.common.response.TokenResponseDTO; import com.tikitaka.naechinso.global.config.security.dto.JwtDTO; import com.tikitaka.naechinso.global.config.security.jwt.JwtTokenProvider; @@ -43,7 +48,7 @@ public class SmsCertificationServiceImpl implements SmsCertificationService { private final RedisService redisService; private final JwtTokenProvider jwtTokenProvider; private final MemberRepository memberRepository; - private final MemberService memberService; + private final RecommendService recommendService; private final String VERIFICATION_PREFIX = "sms:"; private final int VERIFICATION_TIME_LIMIT = 3 * 60; @@ -89,13 +94,13 @@ public String sendVerificationMessage(String to) { /** * 인증번호를 검증한다 - * @param smsCertificationRequestDto {phoneNumber: 휴대폰 번호, code: 인증번호} + * @param requestDTO {phoneNumber: 휴대폰 번호, code: 인증번호} * @return TokenResponseDTO { accessToken, refreshToken } */ @Override - public TokenResponseDTO verifyCode(SmsCertificationRequestDTO smsCertificationRequestDto) { - String phoneNumber = smsCertificationRequestDto.getPhoneNumber(); - String code = smsCertificationRequestDto.getCode(); + public SmsCertificationSuccessResponseDTO verifyCode(SmsCertificationRequestDTO requestDTO) { + String phoneNumber = requestDTO.getPhoneNumber(); + String code = requestDTO.getCode(); String key = VERIFICATION_PREFIX + phoneNumber; //redis 에 해당 번호의 키가 없는 경우는 인증번호(3분) 만료로 처리 @@ -110,40 +115,37 @@ public TokenResponseDTO verifyCode(SmsCertificationRequestDTO smsCertificationRe //redis 인증 필터 성공하면 try { - /* VERIFY FLOW - * -> 아직 MemberDetail 작성한 회원이 아닐 경우 - * 1. 이미 추천사를 받은 신규회원 - * 2. 추천사를 받아야 하는 신규회원 - * 3. 추천사 써주려는 신규회원 - * 4. 추천 요청을 받아서 추천사를 써주는 신규회원 - * * 입력이 다 되었는지 검증, 안되면 register 토큰 발급 - * - * -> MemberDetail 검증 완료된 회원 - * 5. 즉시 마이페이지 이동 - * */ - - - //가입 안된 회원일 경우 null 리턴 + //redis 에서 번호 제거 + redisService.deleteValues(key); + + //추천 받은 정보가 있는지 + Boolean recommendReceived = recommendService.existsByReceiverPhone(phoneNumber); + List recommendDTOList = recommendService.findAllBySenderPhone(phoneNumber); + + //가입 안된 회원일 경우 registerToken 리턴 Optional checkMember = memberRepository.findByPhone(phoneNumber); if (checkMember.isEmpty()) { - return null; - } + String registerToken = jwtTokenProvider.generateRegisterToken(new JwtDTO(phoneNumber)); - if (checkMember.get().getDetail() != null) { - System.out.println("checkMember.get().getDetail() = " + checkMember.get().getDetail()); - } else { - System.out.println("detail is null"); + return SmsCertificationSuccessResponseDTO.builder() + .registerToken(registerToken) + .recommendRequests(recommendDTOList) + .recommendReceived(recommendReceived) + .build(); } //이미 가입한 회원이면 //인증한 휴대폰 번호로 로그인 후 토큰 생성 - TokenResponseDTO tokenResponseDTO = memberService.login(phoneNumber); - - //redis 에서 번호 제거 - redisService.deleteValues(key); - - //토큰 반환 - return tokenResponseDTO; + TokenResponseDTO tokenResponseDTO + = jwtTokenProvider.generateToken(new JwtDTO(phoneNumber)); + + //액세스 + 리프레시 토큰 반환 + return SmsCertificationSuccessResponseDTO.builder() + .accessToken(tokenResponseDTO.getAccessToken()) + .refreshToken(tokenResponseDTO.getRefreshToken()) + .recommendRequests(recommendDTOList) + .recommendReceived(recommendReceived) + .build(); } catch (Exception e) { e.printStackTrace(); throw new InternalServerException("jwt 토큰 생성 에러"); diff --git a/src/main/java/com/tikitaka/naechinso/domain/sms/dto/SmsCertificationSuccessResponseDTO.java b/src/main/java/com/tikitaka/naechinso/domain/sms/dto/SmsCertificationSuccessResponseDTO.java new file mode 100644 index 0000000..501a78e --- /dev/null +++ b/src/main/java/com/tikitaka/naechinso/domain/sms/dto/SmsCertificationSuccessResponseDTO.java @@ -0,0 +1,27 @@ +package com.tikitaka.naechinso.domain.sms.dto; + +import com.fasterxml.jackson.annotation.JsonInclude; +import com.tikitaka.naechinso.domain.recommend.dto.RecommendDTO; +import lombok.*; + +import java.util.ArrayList; +import java.util.List; + +@AllArgsConstructor +@NoArgsConstructor +@Getter +@Builder +@ToString +@JsonInclude(JsonInclude.Include.NON_NULL) //NULL 필드 가림 +public class SmsCertificationSuccessResponseDTO { + private String accessToken; + private String refreshToken; + private String registerToken; + + //receiver 는 있지만 sender 는 없는 Recommend 를 가져옴 (추천 요청) + @Builder.Default + private List recommendRequests = new ArrayList<>(); + + //추천 받았는지 여부, true 면 유효한 유저 + private Boolean recommendReceived = false; +} diff --git a/src/main/java/com/tikitaka/naechinso/global/common/response/TokenResponseDTO.java b/src/main/java/com/tikitaka/naechinso/global/common/response/TokenResponseDTO.java index 46a6499..e5032d5 100644 --- a/src/main/java/com/tikitaka/naechinso/global/common/response/TokenResponseDTO.java +++ b/src/main/java/com/tikitaka/naechinso/global/common/response/TokenResponseDTO.java @@ -1,5 +1,6 @@ package com.tikitaka.naechinso.global.common.response; +import com.fasterxml.jackson.annotation.JsonInclude; import lombok.*; /** JWT Token 응답 Dto @@ -9,7 +10,10 @@ @NoArgsConstructor @AllArgsConstructor @Builder +@JsonInclude(JsonInclude.Include.NON_NULL) //NULL 필드 가림 public class TokenResponseDTO { private String accessToken; private String refreshToken; + private String registerToken; + private Boolean recommendReceived; } diff --git a/src/main/java/com/tikitaka/naechinso/global/config/security/SecurityConfig.java b/src/main/java/com/tikitaka/naechinso/global/config/security/SecurityConfig.java index 5a454d6..63a0f04 100644 --- a/src/main/java/com/tikitaka/naechinso/global/config/security/SecurityConfig.java +++ b/src/main/java/com/tikitaka/naechinso/global/config/security/SecurityConfig.java @@ -58,6 +58,7 @@ public SecurityFilterChain filterChain(HttpSecurity http) throws Exception { .antMatchers("/member/login").permitAll() .antMatchers("/member/join").permitAll() .antMatchers("/sms/**").permitAll() + .antMatchers("/recommend/").permitAll() .anyRequest().authenticated() .and() .headers().frameOptions().disable(); diff --git a/src/main/java/com/tikitaka/naechinso/global/config/security/jwt/JwtTokenProvider.java b/src/main/java/com/tikitaka/naechinso/global/config/security/jwt/JwtTokenProvider.java index 47e7d3d..000ba97 100644 --- a/src/main/java/com/tikitaka/naechinso/global/config/security/jwt/JwtTokenProvider.java +++ b/src/main/java/com/tikitaka/naechinso/global/config/security/jwt/JwtTokenProvider.java @@ -32,9 +32,8 @@ public class JwtTokenProvider { private String JWT_SECRET; /** 토큰 유효 시간 (ms) */ - private static final long JWT_EXPIRATION_MS = 1000L * 60 * 30; //30분 + private static final long JWT_EXPIRATION_MS = 1000L * 60 * 40; //40분 private static final long REFRESH_TOKEN_EXPIRATION_MS = 1000L * 60 * 60 * 24 * 7; //7일 - private static final String AUTHORITIES_KEY = "role"; //권한 정보 컬럼명 public String generateAccessToken(JwtDTO jwtDTO) { @@ -95,6 +94,17 @@ public TokenResponseDTO generateToken(JwtDTO jwtDto) .build(); } + /** 회원가입 전용 Register Token 생성 + * @param jwtDto 인증 요청하는 유저 정보 + */ + public String generateRegisterToken(JwtDTO jwtDto) + throws HttpServerErrorException.InternalServerError { + //권한 가져오기 + final String registerToken = generateAccessToken(jwtDto); + return registerToken; + } + + public Authentication getAuthentication(String accessToken) { Claims claims = parseClaims(accessToken); From ee390c27ac1acac72fa8e1748a9c08c8c6161a01 Mon Sep 17 00:00:00 2001 From: gengminy Date: Sat, 1 Oct 2022 23:28:49 +0900 Subject: [PATCH 09/72] =?UTF-8?q?:hammer:=20fix(jwt):=20=EC=9C=A0=EC=A0=80?= =?UTF-8?q?=20=EA=B6=8C=ED=95=9C=20=EC=84=A4=EC=A0=95=20=EC=B6=94=EA=B0=80?= =?UTF-8?q?=20#6?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../domain/member/constant/Role.java | 25 +++++++++++++++ .../member/dto/MemberCommonResponseDto.java | 5 +++ .../member/dto/MemberDetailResponseDto.java | 4 +++ .../domain/member/entity/Member.java | 6 ++++ .../domain/recommend/RecommendController.java | 17 +++++++++- .../sms/SmsCertificationServiceImpl.java | 2 +- .../global/config/security/MemberAdapter.java | 12 +++++-- .../security/UserDetailServiceImpl.java | 11 ++----- .../global/config/security/dto/JwtDTO.java | 12 +++++-- .../security/jwt/JwtAuthenticationFilter.java | 8 ++--- .../config/security/jwt/JwtTokenProvider.java | 31 ++++++++++++++----- .../naechinso/global/error/ErrorResponse.java | 2 +- 12 files changed, 108 insertions(+), 27 deletions(-) create mode 100644 src/main/java/com/tikitaka/naechinso/domain/member/constant/Role.java diff --git a/src/main/java/com/tikitaka/naechinso/domain/member/constant/Role.java b/src/main/java/com/tikitaka/naechinso/domain/member/constant/Role.java new file mode 100644 index 0000000..9f471ef --- /dev/null +++ b/src/main/java/com/tikitaka/naechinso/domain/member/constant/Role.java @@ -0,0 +1,25 @@ +package com.tikitaka.naechinso.domain.member.constant; + +import com.fasterxml.jackson.annotation.JsonCreator; +import lombok.AllArgsConstructor; +import lombok.Getter; + +@Getter +@AllArgsConstructor +public enum Role { + USER("ROLE_USER"), + ADMIN("ROLE_ADMIN"); + + private final String detail; + + //Enum Validation 을 위한 코드, enum 에 속하지 않으면 null 리턴 + @JsonCreator + public static Role fromRole(String val){ + for(Role role : Role.values()){ + if(role.name().equals(val)){ + return role; + } + } + return null; + } +} diff --git a/src/main/java/com/tikitaka/naechinso/domain/member/dto/MemberCommonResponseDto.java b/src/main/java/com/tikitaka/naechinso/domain/member/dto/MemberCommonResponseDto.java index 7a2281b..e5b74f2 100644 --- a/src/main/java/com/tikitaka/naechinso/domain/member/dto/MemberCommonResponseDto.java +++ b/src/main/java/com/tikitaka/naechinso/domain/member/dto/MemberCommonResponseDto.java @@ -1,6 +1,7 @@ package com.tikitaka.naechinso.domain.member.dto; import com.tikitaka.naechinso.domain.member.constant.Gender; +import com.tikitaka.naechinso.domain.member.constant.Role; import com.tikitaka.naechinso.domain.member.entity.Member; import lombok.*; @@ -14,8 +15,11 @@ @Builder @ToString public class MemberCommonResponseDto { + private String phone; + private Role role; + private String name; private Gender gender; @@ -25,6 +29,7 @@ public class MemberCommonResponseDto { public static MemberCommonResponseDto of(Member member) { MemberCommonResponseDto res = MemberCommonResponseDto.builder() .phone(member.getPhone()) + .role(member.getRole()) .name(member.getName()) .gender(member.getGender()) .age(member.getAge()) diff --git a/src/main/java/com/tikitaka/naechinso/domain/member/dto/MemberDetailResponseDto.java b/src/main/java/com/tikitaka/naechinso/domain/member/dto/MemberDetailResponseDto.java index 2a0b5ea..ed2815f 100644 --- a/src/main/java/com/tikitaka/naechinso/domain/member/dto/MemberDetailResponseDto.java +++ b/src/main/java/com/tikitaka/naechinso/domain/member/dto/MemberDetailResponseDto.java @@ -1,6 +1,7 @@ package com.tikitaka.naechinso.domain.member.dto; import com.tikitaka.naechinso.domain.member.constant.Gender; +import com.tikitaka.naechinso.domain.member.constant.Role; import com.tikitaka.naechinso.domain.member.entity.Member; import com.tikitaka.naechinso.domain.member.entity.MemberDetail; import com.tikitaka.naechinso.global.error.ErrorCode; @@ -26,6 +27,8 @@ public class MemberDetailResponseDto { //추천인 정보 private String phone; + private Role role; + private String name; private Gender gender; @@ -84,6 +87,7 @@ private static MemberDetailResponseDto buildDetail(MemberDetail detail) { //멤버 정보가 연결되어 있으면 가져옴 if (member != null) { dtoBuilder.phone(member.getPhone()) + .role(member.getRole()) .name(member.getName()) .gender(member.getGender()) .age(member.getAge()); diff --git a/src/main/java/com/tikitaka/naechinso/domain/member/entity/Member.java b/src/main/java/com/tikitaka/naechinso/domain/member/entity/Member.java index e92cabc..4d2fe06 100644 --- a/src/main/java/com/tikitaka/naechinso/domain/member/entity/Member.java +++ b/src/main/java/com/tikitaka/naechinso/domain/member/entity/Member.java @@ -2,6 +2,7 @@ import com.fasterxml.jackson.annotation.JsonIgnore; import com.tikitaka.naechinso.domain.member.constant.Gender; +import com.tikitaka.naechinso.domain.member.constant.Role; import com.tikitaka.naechinso.domain.recommend.entity.Recommend; import com.tikitaka.naechinso.global.config.entity.BaseEntity; import lombok.*; @@ -32,6 +33,11 @@ public class Member extends BaseEntity { @Column(name = "mem_phone") private String phone; + @Column(name = "mem_role", columnDefinition = "Text default 'ROLE_USER'") + @Builder.Default + @Enumerated(EnumType.STRING) + private Role role = Role.USER; + @Column(name = "mem_name") private String name; diff --git a/src/main/java/com/tikitaka/naechinso/domain/recommend/RecommendController.java b/src/main/java/com/tikitaka/naechinso/domain/recommend/RecommendController.java index 39645b9..ffc1049 100644 --- a/src/main/java/com/tikitaka/naechinso/domain/recommend/RecommendController.java +++ b/src/main/java/com/tikitaka/naechinso/domain/recommend/RecommendController.java @@ -74,7 +74,22 @@ public CommonApiResponse createRecommendRequest( // //제일 아래에 있어야함 // @GetMapping("/{uuid}") -// @ApiOperation(value = "추천 요청 uuid 를 가진 추천사 엔티티를 가져온다") +// @ApiOperation(value = "추천 요청받은 uuid 를 가진 추천사 정보를 가져온다") +// public CommonApiResponse getRecommendByUuid( +// HttpServletRequest request, +// @PathVariable("uuid") String uuid, +// @Valid @RequestBody RecommendRequestDTO dto) +// { +// String registerToken = request.getHeader("Authorization"); +// String phone = parseRegisterToken(registerToken); +// +//// RecommendDTO recommendDTO = recommendService.findAllRecommendRequestsByUuid(uuid); +// return CommonApiResponse.of(recommendDTO); +// } + + // //제일 아래에 있어야함 +// @PatchMapping("/{uuid}") +// @ApiOperation(value = "요청받은 uuid 추천사에 추천인을 등록한다") // public CommonApiResponse getRecommendByUuid( // HttpServletRequest request, // @PathVariable("uuid") String uuid, diff --git a/src/main/java/com/tikitaka/naechinso/domain/sms/SmsCertificationServiceImpl.java b/src/main/java/com/tikitaka/naechinso/domain/sms/SmsCertificationServiceImpl.java index 330009a..b2dbdf3 100644 --- a/src/main/java/com/tikitaka/naechinso/domain/sms/SmsCertificationServiceImpl.java +++ b/src/main/java/com/tikitaka/naechinso/domain/sms/SmsCertificationServiceImpl.java @@ -137,7 +137,7 @@ public SmsCertificationSuccessResponseDTO verifyCode(SmsCertificationRequestDTO //이미 가입한 회원이면 //인증한 휴대폰 번호로 로그인 후 토큰 생성 TokenResponseDTO tokenResponseDTO - = jwtTokenProvider.generateToken(new JwtDTO(phoneNumber)); + = jwtTokenProvider.generateToken(new JwtDTO(phoneNumber, checkMember.get().getRole().getDetail())); //액세스 + 리프레시 토큰 반환 return SmsCertificationSuccessResponseDTO.builder() diff --git a/src/main/java/com/tikitaka/naechinso/global/config/security/MemberAdapter.java b/src/main/java/com/tikitaka/naechinso/global/config/security/MemberAdapter.java index 35b6514..64227fd 100644 --- a/src/main/java/com/tikitaka/naechinso/global/config/security/MemberAdapter.java +++ b/src/main/java/com/tikitaka/naechinso/global/config/security/MemberAdapter.java @@ -1,11 +1,14 @@ package com.tikitaka.naechinso.global.config.security; +import com.tikitaka.naechinso.domain.member.constant.Role; import com.tikitaka.naechinso.domain.member.entity.Member; import lombok.Getter; +import org.springframework.security.core.GrantedAuthority; import org.springframework.security.core.authority.SimpleGrantedAuthority; import org.springframework.security.core.userdetails.User; -import java.util.List; +import java.util.*; +import java.util.stream.Collectors; /** * UserDetails 를 구현한 어댑터 @@ -18,8 +21,13 @@ public class MemberAdapter extends User { private Member member; public MemberAdapter(Member member) { - super(member.getPhone(), "", List.of(new SimpleGrantedAuthority("ROLE_USER"))); + super(member.getPhone(), "", authorities(member.getRole())); this.member = member; } + private static Collection authorities(Role userRole) { + Collection role = new ArrayList<>(); + role.add(new SimpleGrantedAuthority(userRole.getDetail())); + return role; + } } diff --git a/src/main/java/com/tikitaka/naechinso/global/config/security/UserDetailServiceImpl.java b/src/main/java/com/tikitaka/naechinso/global/config/security/UserDetailServiceImpl.java index 6b2e5d2..3d03d24 100644 --- a/src/main/java/com/tikitaka/naechinso/global/config/security/UserDetailServiceImpl.java +++ b/src/main/java/com/tikitaka/naechinso/global/config/security/UserDetailServiceImpl.java @@ -18,14 +18,9 @@ public class UserDetailServiceImpl implements UserDetailsService { @Override public UserDetails loadUserByUsername(String phone) throws UsernameNotFoundException { Member member = memberRepository.findByPhone(phone) - .orElseThrow(() -> { throw new UsernameNotFoundException(phone + "-> DB에 없는 유저"); }); - + .orElseThrow(() -> { + throw new UsernameNotFoundException(phone + "-> DB에 없는 유저"); + }); return new MemberAdapter(member); -// return new User(member.getPhone(), "", Collections.singletonList(new SimpleGrantedAuthority("ROLE_USER"))); } -// -// //DB에 존재하는 유저일 경우 UserDetails로 만들어서 반환 -// private UserDetails createUserDetails(Member member) { -// GrantedAuthority grantedAuthority = new SimpleGrantedAuthority("ROLE_USER"); -// } } \ No newline at end of file diff --git a/src/main/java/com/tikitaka/naechinso/global/config/security/dto/JwtDTO.java b/src/main/java/com/tikitaka/naechinso/global/config/security/dto/JwtDTO.java index 7e6c0af..56e1a81 100644 --- a/src/main/java/com/tikitaka/naechinso/global/config/security/dto/JwtDTO.java +++ b/src/main/java/com/tikitaka/naechinso/global/config/security/dto/JwtDTO.java @@ -11,7 +11,7 @@ public class JwtDTO { // private Long id; private String phoneNumber; - private String authorities; + private String role; // public JwtDTO(User user) { //// this.id = user.getId(); @@ -20,9 +20,17 @@ public class JwtDTO { // this.authorities = user.getAuthorities().toString(); // } + /* 역할 정보가 없음 (registerToken) */ public JwtDTO(String phoneNumber) { this.phoneNumber = phoneNumber; //임시 권한 부여 - this.authorities = "ROLE_USER"; + this.role = null; + } + + /* 역할 정보가 있음 (accessToken) */ + public JwtDTO(String phoneNumber, String role) { + this.phoneNumber = phoneNumber; + //임시 권한 부여 + this.role = role; } } \ No newline at end of file diff --git a/src/main/java/com/tikitaka/naechinso/global/config/security/jwt/JwtAuthenticationFilter.java b/src/main/java/com/tikitaka/naechinso/global/config/security/jwt/JwtAuthenticationFilter.java index 9a10146..2ab600d 100644 --- a/src/main/java/com/tikitaka/naechinso/global/config/security/jwt/JwtAuthenticationFilter.java +++ b/src/main/java/com/tikitaka/naechinso/global/config/security/jwt/JwtAuthenticationFilter.java @@ -46,7 +46,7 @@ protected void doFilterInternal(HttpServletRequest request, HttpServletResponse // } if (StringUtils.isNotBlank(jwt) && jwtTokenService.validateToken(jwt)) { - Authentication authentication = jwtTokenService.getAuthentication(jwt); //authentication 획득 + Authentication authentication = jwtTokenService.getAuthentication(request, jwt); //authentication 획득 //Security 세션에서 계속 사용하기 위해 SecurityContext에 Authentication 등록 SecurityContextHolder.getContext().setAuthentication(authentication); @@ -55,9 +55,7 @@ protected void doFilterInternal(HttpServletRequest request, HttpServletResponse request.setAttribute("exception", ErrorCode.NO_TOKEN.getCode()); } - if (!jwtTokenService.validateToken(jwt, request)){ - - } + jwtTokenService.validateToken(request, jwt); } } catch (Exception ex) { logger.error("Security Context에 해당 토큰을 등록할 수 없습니다", ex); @@ -70,7 +68,6 @@ protected void doFilterInternal(HttpServletRequest request, HttpServletResponse filterChain.doFilter(request, response); } - private String resolveToken(HttpServletRequest request) { String bearerToken = request.getHeader("Authorization"); //Prefix 로 Bearer 가 있으면 제거 @@ -79,5 +76,6 @@ private String resolveToken(HttpServletRequest request) { } //Prefix 가 없으면 그대로 return bearerToken; + } } \ No newline at end of file diff --git a/src/main/java/com/tikitaka/naechinso/global/config/security/jwt/JwtTokenProvider.java b/src/main/java/com/tikitaka/naechinso/global/config/security/jwt/JwtTokenProvider.java index 000ba97..4d48ae1 100644 --- a/src/main/java/com/tikitaka/naechinso/global/config/security/jwt/JwtTokenProvider.java +++ b/src/main/java/com/tikitaka/naechinso/global/config/security/jwt/JwtTokenProvider.java @@ -32,6 +32,7 @@ public class JwtTokenProvider { private String JWT_SECRET; /** 토큰 유효 시간 (ms) */ + private static final long REGISTER_TOKEN_EXPIRATION_MS = 1000L * 60 * 60; //60분 private static final long JWT_EXPIRATION_MS = 1000L * 60 * 40; //40분 private static final long REFRESH_TOKEN_EXPIRATION_MS = 1000L * 60 * 60 * 24 * 7; //7일 private static final String AUTHORITIES_KEY = "role"; //권한 정보 컬럼명 @@ -49,7 +50,7 @@ public String generateAccessToken(JwtDTO jwtDTO) { .setIssuer("naechinso") .setIssuedAt(now) // 생성일자 지정(현재) .setSubject(jwtDTO.getPhoneNumber()) // 사용자(principal => phoneNumber) - .claim(AUTHORITIES_KEY, jwtDTO.getAuthorities()) //권한 설정 + .claim(AUTHORITIES_KEY, jwtDTO.getRole()) //권한 설정 .setExpiration(accessTokenExpiresIn) // 만료일자 .signWith(SignatureAlgorithm.HS512, encodedKey) // signature에 들어갈 secret 값 세팅 .compact(); @@ -95,24 +96,40 @@ public TokenResponseDTO generateToken(JwtDTO jwtDto) } /** 회원가입 전용 Register Token 생성 - * @param jwtDto 인증 요청하는 유저 정보 + * @param jwtDTO 인증 요청하는 유저 정보 */ - public String generateRegisterToken(JwtDTO jwtDto) + public String generateRegisterToken(JwtDTO jwtDTO) throws HttpServerErrorException.InternalServerError { - //권한 가져오기 - final String registerToken = generateAccessToken(jwtDto); + final String encodedKey = Base64.getEncoder().encodeToString(JWT_SECRET.getBytes()); + final Date now = new Date(); + final Date registerTokenExpiresIn = new Date(now.getTime() + REGISTER_TOKEN_EXPIRATION_MS); + + //권한 정보를 제외하고 생성 + final String registerToken = Jwts.builder() + .setHeaderParam(Header.TYPE, Header.JWT_TYPE) + .setIssuer("naechinso") + .setIssuedAt(now) // 생성일자 지정(현재) + .setSubject(jwtDTO.getPhoneNumber()) // 사용자(principal => phoneNumber) + .setExpiration(registerTokenExpiresIn) // 만료일자 + .signWith(SignatureAlgorithm.HS512, encodedKey) // signature 에 들어갈 secret 값 세팅 + .compact(); + return registerToken; } - public Authentication getAuthentication(String accessToken) { + public Authentication getAuthentication(HttpServletRequest request, String accessToken) { Claims claims = parseClaims(accessToken); + System.out.println("claims = " + claims); // + if (claims.get(AUTHORITIES_KEY) == null) { + request.setAttribute("exception", ErrorCode.INVALID_AUTH_TOKEN.getCode()); throw new UnauthorizedException(ErrorCode.INVALID_AUTH_TOKEN); } UserDetails principal = loginService.loadUserByUsername(claims.getSubject()); + return new UsernamePasswordAuthenticationToken(principal, "", principal.getAuthorities()); } @@ -149,7 +166,7 @@ public boolean validateToken(String token) { * @param token 검사하려는 JWT 토큰 * @returns boolean * */ - public boolean validateToken(String token, HttpServletRequest request) { + public boolean validateToken(HttpServletRequest request, String token) { final String encodedKey = Base64.getEncoder().encodeToString(JWT_SECRET.getBytes()); try { Jwts.parser().setSigningKey(encodedKey).parseClaimsJws(token); diff --git a/src/main/java/com/tikitaka/naechinso/global/error/ErrorResponse.java b/src/main/java/com/tikitaka/naechinso/global/error/ErrorResponse.java index 1233a13..45875ea 100644 --- a/src/main/java/com/tikitaka/naechinso/global/error/ErrorResponse.java +++ b/src/main/java/com/tikitaka/naechinso/global/error/ErrorResponse.java @@ -50,7 +50,7 @@ public static ErrorResponse of(ErrorCode errorCode, BindingResult bindingResult) public static JSONObject jsonOf(ErrorCode errorCode) { JSONObject jsonObject = new JSONObject(); jsonObject.put("timestamp", LocalDateTime.now()); - jsonObject.put("success", "false"); + jsonObject.put("success", false); jsonObject.put("message", errorCode.getDetail()); jsonObject.put("status", errorCode.getHttpStatus().value()); jsonObject.put("code", errorCode.getCode()); From 54be8d116538c600cecac3c21607697a242ea9ad Mon Sep 17 00:00:00 2001 From: gengminy Date: Sun, 2 Oct 2022 01:04:26 +0900 Subject: [PATCH 10/72] =?UTF-8?q?:rocket:=20feat(join):=20=EA=B0=80?= =?UTF-8?q?=EC=9E=85=20=ED=94=8C=EB=A1=9C=EC=9A=B0=20=EC=B4=88=EA=B8=B0=20?= =?UTF-8?q?=EA=B5=AC=EC=84=B1=20#20?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../domain/recommend/RecommendController.java | 72 ++++++------ .../domain/recommend/RecommendRepository.java | 5 + .../domain/recommend/RecommendService.java | 75 +++++++++++-- .../dto/RecommendAcceptRequestDTO.java | 103 ++++++++++++++++++ .../domain/recommend/dto/RecommendDTO.java | 12 +- .../recommend/dto/RecommendMetaDTO.java | 18 --- .../recommend/dto/RecommendRequestDTO.java | 9 +- .../domain/recommend/entity/Recommend.java | 11 +- .../config/security/SecurityConfig.java | 1 + .../naechinso/global/error/ErrorCode.java | 5 + 10 files changed, 237 insertions(+), 74 deletions(-) create mode 100644 src/main/java/com/tikitaka/naechinso/domain/recommend/dto/RecommendAcceptRequestDTO.java delete mode 100644 src/main/java/com/tikitaka/naechinso/domain/recommend/dto/RecommendMetaDTO.java diff --git a/src/main/java/com/tikitaka/naechinso/domain/recommend/RecommendController.java b/src/main/java/com/tikitaka/naechinso/domain/recommend/RecommendController.java index ffc1049..fe806a4 100644 --- a/src/main/java/com/tikitaka/naechinso/domain/recommend/RecommendController.java +++ b/src/main/java/com/tikitaka/naechinso/domain/recommend/RecommendController.java @@ -1,10 +1,7 @@ package com.tikitaka.naechinso.domain.recommend; import com.tikitaka.naechinso.domain.member.entity.Member; -import com.tikitaka.naechinso.domain.recommend.dto.RecommendDTO; -import com.tikitaka.naechinso.domain.recommend.dto.RecommendJoinRequestDTO; -import com.tikitaka.naechinso.domain.recommend.dto.RecommendListResponseDTO; -import com.tikitaka.naechinso.domain.recommend.dto.RecommendRequestDTO; +import com.tikitaka.naechinso.domain.recommend.dto.*; import com.tikitaka.naechinso.global.annotation.AuthMember; import com.tikitaka.naechinso.global.config.CommonApiResponse; import com.tikitaka.naechinso.global.config.security.jwt.JwtTokenProvider; @@ -19,6 +16,7 @@ import javax.servlet.http.HttpServletRequest; import javax.validation.Valid; +import java.util.List; @Slf4j @RestController @@ -53,6 +51,17 @@ public CommonApiResponse createRecommendNewSender( return CommonApiResponse.of(recommendDTO); } + @GetMapping("/find") + @ApiOperation(value = "[Admin]모든 추천사 정보를 가져온다 (AccessToken)") + public CommonApiResponse> getAllRecommends( + @ApiIgnore @AuthMember Member member) + { + if (member == null) { + throw new UnauthorizedException(ErrorCode.UNAUTHORIZED_USER); + } + return CommonApiResponse.of(recommendService.findAll()); + } + @PostMapping("/request") @ApiOperation(value = "다른 유저에게 추천서 작성을 요청한다 (registerToken 필요)") public CommonApiResponse createRecommendRequest( @@ -71,36 +80,35 @@ public CommonApiResponse createRecommendRequest( + //제일 아래에 있어야함 + @GetMapping("/{uuid}") + @ApiOperation(value = "추천 요청받은 uuid 를 가진 추천사 정보를 가져온다 (Register / AccessToken 필요)") + public CommonApiResponse getRecommendByUuid( + HttpServletRequest request, + @PathVariable("uuid") String uuid) + { + //토큰 장착 확인 + String token = request.getHeader("Authorization"); + String phone = parseRegisterToken(token); + + RecommendDTO recommendDTO = RecommendDTO.of(recommendService.findByUuid(uuid)); + return CommonApiResponse.of(recommendDTO); + } -// //제일 아래에 있어야함 -// @GetMapping("/{uuid}") -// @ApiOperation(value = "추천 요청받은 uuid 를 가진 추천사 정보를 가져온다") -// public CommonApiResponse getRecommendByUuid( -// HttpServletRequest request, -// @PathVariable("uuid") String uuid, -// @Valid @RequestBody RecommendRequestDTO dto) -// { -// String registerToken = request.getHeader("Authorization"); -// String phone = parseRegisterToken(registerToken); -// -//// RecommendDTO recommendDTO = recommendService.findAllRecommendRequestsByUuid(uuid); -// return CommonApiResponse.of(recommendDTO); -// } + @PatchMapping("/{uuid}") + @ApiOperation(value = "요청받은 uuid 추천사에 자신을 추천인으로 등록한다 (Register / AccessToken 필요)") + public CommonApiResponse getRecommendByUuid( + HttpServletRequest request, + @PathVariable("uuid") String uuid, + @Valid @RequestBody RecommendAcceptRequestDTO dto) + { + //토큰 장착 확인 + String token = request.getHeader("Authorization"); + String phone = parseRegisterToken(token); - // //제일 아래에 있어야함 -// @PatchMapping("/{uuid}") -// @ApiOperation(value = "요청받은 uuid 추천사에 추천인을 등록한다") -// public CommonApiResponse getRecommendByUuid( -// HttpServletRequest request, -// @PathVariable("uuid") String uuid, -// @Valid @RequestBody RecommendRequestDTO dto) -// { -// String registerToken = request.getHeader("Authorization"); -// String phone = parseRegisterToken(registerToken); -// -//// RecommendDTO recommendDTO = recommendService.findAllRecommendRequestsByUuid(uuid); -// return CommonApiResponse.of(recommendDTO); -// } + RecommendDTO recommendDTO = recommendService.updateRecommendRequest(uuid, phone, dto); + return CommonApiResponse.of(recommendDTO); + } private String parseRegisterToken(String registerToken) { if (StringUtils.isBlank(registerToken) || !jwtTokenService.validateToken(registerToken)) { diff --git a/src/main/java/com/tikitaka/naechinso/domain/recommend/RecommendRepository.java b/src/main/java/com/tikitaka/naechinso/domain/recommend/RecommendRepository.java index da597a8..a0c2ae7 100644 --- a/src/main/java/com/tikitaka/naechinso/domain/recommend/RecommendRepository.java +++ b/src/main/java/com/tikitaka/naechinso/domain/recommend/RecommendRepository.java @@ -8,6 +8,7 @@ import java.util.List; import java.util.Optional; +import java.util.UUID; @Repository public interface RecommendRepository extends JpaRepository { @@ -16,5 +17,9 @@ public interface RecommendRepository extends JpaRepository { List findAllBySender_Id(Long id); List findAllBySenderPhone(String phone); + List findAllByIdNotNull(); + + Optional findByUuid(String uuid); + Boolean existsByReceiverPhone(String phone); } diff --git a/src/main/java/com/tikitaka/naechinso/domain/recommend/RecommendService.java b/src/main/java/com/tikitaka/naechinso/domain/recommend/RecommendService.java index 67c80f3..975a2b1 100644 --- a/src/main/java/com/tikitaka/naechinso/domain/recommend/RecommendService.java +++ b/src/main/java/com/tikitaka/naechinso/domain/recommend/RecommendService.java @@ -2,10 +2,7 @@ import com.tikitaka.naechinso.domain.member.MemberRepository; import com.tikitaka.naechinso.domain.member.entity.Member; -import com.tikitaka.naechinso.domain.recommend.dto.RecommendDTO; -import com.tikitaka.naechinso.domain.recommend.dto.RecommendJoinRequestDTO; -import com.tikitaka.naechinso.domain.recommend.dto.RecommendListResponseDTO; -import com.tikitaka.naechinso.domain.recommend.dto.RecommendRequestDTO; +import com.tikitaka.naechinso.domain.recommend.dto.*; import com.tikitaka.naechinso.domain.recommend.entity.Recommend; import com.tikitaka.naechinso.global.error.ErrorCode; import com.tikitaka.naechinso.global.error.exception.BadRequestException; @@ -17,6 +14,7 @@ import java.util.ArrayList; import java.util.List; import java.util.Optional; +import java.util.UUID; @Service @RequiredArgsConstructor @@ -39,6 +37,11 @@ public RecommendDTO createRecommendJoin(String senderPhone, RecommendJoinRequest throw new BadRequestException(ErrorCode.USER_ALREADY_EXIST); } + //자기 자신을 추천하면 종료 + if (senderPhone == dto.getReceiverPhone()) { + throw new BadRequestException(ErrorCode.CANNOT_RECOMMEND_MYSELF); + } + Member sender = dto.toSender(senderPhone); Member receiver = memberRepository.findByPhone(dto.getReceiverPhone()) @@ -70,6 +73,11 @@ public RecommendDTO createRecommendJoin(String senderPhone, RecommendJoinRequest } public RecommendDTO createRecommendRequest(String receiverPhone, RecommendRequestDTO dto) { + //이미 추천사 요청을 보냄 + if (existsByReceiverPhone(receiverPhone)) { + throw(new NotFoundException(ErrorCode.RECOMMEND_ALREADY_EXIST)); + } + Member receiver = dto.toReceiver(receiverPhone); Recommend recommend = Recommend.builder() .sender(null) @@ -86,6 +94,55 @@ public RecommendDTO createRecommendRequest(String receiverPhone, RecommendReques return RecommendDTO.of(recommend); } + public RecommendDTO updateRecommendRequest(String uuid, String senderPhone, RecommendAcceptRequestDTO dto) { + + Recommend recommend = findByUuid(uuid); + + //자기 자신을 추천하면 종료 + if (senderPhone == recommend.getReceiverPhone()) { + throw new BadRequestException(ErrorCode.CANNOT_RECOMMEND_MYSELF); + } + + //유저가 없으면 회원가입 시킴 있으면 그대로 사용 + Member sender = memberRepository.findByPhone(senderPhone) + .orElse(dto.toSender(senderPhone)); + + recommend.setSender(sender); + recommend.setSenderPhone(senderPhone); + recommend.setSenderName(dto.getName()); + recommend.setSenderAge(dto.getAge()); + recommend.setSenderGender(dto.getGender()); + recommend.setSenderJobName(dto.getJobName()); + recommend.setSenderJobPart(dto.getJobPart()); + recommend.setSenderJobLocation(dto.getJobLocation()); + recommend.setReceiverName(dto.getReceiverName()); + recommend.setReceiverAge(dto.getReceiverAge()); + recommend.setReceiverAppeal(dto.getAppeal()); + recommend.setReceiverGender(dto.getReceiverGender()); + recommend.setReceiverMeet(dto.getMeet()); + recommend.setReceiverPersonality(dto.getPersonality()); + + memberRepository.save(sender); + recommendRepository.save(recommend); + + return RecommendDTO.of(recommend); + } + + + public List findAll() { + List recommendDTOList = new ArrayList<>(); + + recommendRepository.findAllByIdNotNull().forEach( + recommend -> recommendDTOList.add(RecommendDTO.of(recommend)) + ); + + recommendDTOList.forEach( + recommendDTO -> System.out.println("recommendDTO = " + recommendDTO) + ); + + return recommendDTOList; + } + public List findAllBySenderPhone(String phone) { List recommendDTOList = new ArrayList<>(); recommendRepository.findAllBySenderPhone(phone).stream().map( @@ -94,12 +151,10 @@ public List findAllBySenderPhone(String phone) { return recommendDTOList; } -// //링크로 요청한 -// public RecommendDTO findAllRecommendRequestsByUuid(String uuid){ -// RecommendMeta meta = recommendMetaRepository.findByUuid(uuid) -// .orElseThrow(() -> new NotFoundException(ErrorCode.USER_NOT_FOUND)); -// return RecommendDTO.of(meta.getRecommend()); -// } + public Recommend findByUuid(String uuid) { + return recommendRepository.findByUuid(uuid) + .orElseThrow(() -> new NotFoundException(ErrorCode.RECOMMEND_NOT_FOUND)); + } public Boolean existsByReceiverPhone(String phone){ return recommendRepository.existsByReceiverPhone(phone); diff --git a/src/main/java/com/tikitaka/naechinso/domain/recommend/dto/RecommendAcceptRequestDTO.java b/src/main/java/com/tikitaka/naechinso/domain/recommend/dto/RecommendAcceptRequestDTO.java new file mode 100644 index 0000000..51c2d96 --- /dev/null +++ b/src/main/java/com/tikitaka/naechinso/domain/recommend/dto/RecommendAcceptRequestDTO.java @@ -0,0 +1,103 @@ +package com.tikitaka.naechinso.domain.recommend.dto; + +import com.tikitaka.naechinso.domain.member.constant.Gender; +import com.tikitaka.naechinso.domain.member.entity.Member; +import com.tikitaka.naechinso.global.annotation.Enum; +import io.swagger.annotations.ApiModelProperty; +import lombok.*; + +import javax.validation.constraints.*; + +@AllArgsConstructor +@NoArgsConstructor +@Getter +@Builder +@ToString +public class RecommendAcceptRequestDTO { + @ApiModelProperty(example = "닉") + @NotBlank(message = "이름을 입력해주세요") + private String name; + + @ApiModelProperty(example = "M") + @Enum(enumClass = Gender.class, message = "성별 입력이 올바르지 않습니다. M 또는 W가 필요합니다") + private Gender gender; + + @ApiModelProperty(example = "25") + @Min(value = 25, message = "25-33세까지만 가입 가능합니다") + @Max(value = 33, message = "25-33세까지만 가입 가능합니다") + private int age; + + @NotNull(message = "서비스 이용약관 동의가 필요합니다") + @AssertTrue(message = "서비스 이용약관 동의가 필요합니다") + private boolean acceptsService; + + @NotNull(message = "개인정보 이용 동의가 필요합니다") + @AssertTrue(message = "개인정보 이용 동의가 필요합니다") + private boolean acceptsInfo; + + @NotNull(message = "종교 정보 제공 동의가 필요합니다") + @AssertTrue(message = "종교 정보 제공 동의가 필요합니다") + private boolean acceptsReligion; + + @NotNull(message = "위치 정보 제공 동의 여부가 필요합니다") + private boolean acceptsLocation; + + @NotNull(message = "마케팅 동의 여부가 필요합니다") + private boolean acceptsMarketing; + + @ApiModelProperty(example = "카카오") + @NotBlank(message = "직장명을 입력해주세요") + private String jobName; + + @ApiModelProperty(example = "개발자") + @NotBlank(message = "직장 부서를 입력해주세요") + private String jobPart; + + @ApiModelProperty(example = "판교") + @NotBlank(message = "직장 위치를 입력해주세요") + private String jobLocation; + + + @ApiModelProperty(example = "박스") + @NotBlank(message = "친구의 이름을 입력해주세요") + private String receiverName; + + @ApiModelProperty(example = "M") + @Enum(enumClass = Gender.class, message = "친구의 성별 입력이 올바르지 않습니다. M 또는 W가 필요합니다") + private Gender receiverGender; + + @ApiModelProperty(example = "25") + @Min(value = 25, message = "25-33세까지만 추천 및 가입 가능합니다") + @Max(value = 33, message = "25-33세까지만 추천 및 가입 가능합니다") + private int receiverAge; + + @ApiModelProperty(example = "CMC 에서") + @NotBlank(message = "만나게 된 계기를 입력해주세요") + private String meet; + + @ApiModelProperty(example = "최고") + @NotBlank(message = "친구의 성격 키워드를 입력해주세요") + private String personality; + + @ApiModelProperty(example = "짱") + @NotBlank(message = "친구의 매력을 입력해주세요") + private String appeal; + + + public Member toSender(String phone){ + return Member.builder() + .phone(phone) + .name(this.name) + .gender(this.gender) + .age(this.age) + .acceptsService(this.acceptsService) + .acceptsInfo(this.acceptsInfo) + .acceptsReligion(this.acceptsReligion) + .acceptsLocation(this.acceptsLocation) + .acceptsMarketing(this.acceptsMarketing) + .jobName(this.jobName) + .jobPart(this.jobPart) + .jobLocation(this.jobLocation) + .build(); + } +} diff --git a/src/main/java/com/tikitaka/naechinso/domain/recommend/dto/RecommendDTO.java b/src/main/java/com/tikitaka/naechinso/domain/recommend/dto/RecommendDTO.java index 573b7da..5ad551b 100644 --- a/src/main/java/com/tikitaka/naechinso/domain/recommend/dto/RecommendDTO.java +++ b/src/main/java/com/tikitaka/naechinso/domain/recommend/dto/RecommendDTO.java @@ -6,6 +6,7 @@ import lombok.*; import javax.persistence.*; +import java.util.UUID; @AllArgsConstructor @NoArgsConstructor @@ -14,11 +15,9 @@ @ToString public class RecommendDTO { - private String phone; - - private Long senderId; + private String uuid; - private Long receiverId; + private String phone; private String name; @@ -28,6 +27,10 @@ public class RecommendDTO { private String appeal; + private Long senderId; + + private Long receiverId; + public static RecommendDTO of(Recommend recommend) { Long senderId; @@ -45,6 +48,7 @@ public static RecommendDTO of(Recommend recommend) { } return RecommendDTO.builder() + .uuid(recommend.getUuid()) .phone(recommend.getReceiverPhone()) .senderId(senderId) .receiverId(receiverId) diff --git a/src/main/java/com/tikitaka/naechinso/domain/recommend/dto/RecommendMetaDTO.java b/src/main/java/com/tikitaka/naechinso/domain/recommend/dto/RecommendMetaDTO.java deleted file mode 100644 index 69c16df..0000000 --- a/src/main/java/com/tikitaka/naechinso/domain/recommend/dto/RecommendMetaDTO.java +++ /dev/null @@ -1,18 +0,0 @@ -package com.tikitaka.naechinso.domain.recommend.dto; - -import com.tikitaka.naechinso.domain.member.constant.Gender; -import com.tikitaka.naechinso.domain.recommend.entity.Recommend; -import lombok.*; - -import java.util.UUID; - -@AllArgsConstructor -@NoArgsConstructor -@Getter -@Builder -@ToString -public class RecommendMetaDTO { - private UUID uuid; - - private Recommend recommend; -} diff --git a/src/main/java/com/tikitaka/naechinso/domain/recommend/dto/RecommendRequestDTO.java b/src/main/java/com/tikitaka/naechinso/domain/recommend/dto/RecommendRequestDTO.java index eced9bf..cc132e3 100644 --- a/src/main/java/com/tikitaka/naechinso/domain/recommend/dto/RecommendRequestDTO.java +++ b/src/main/java/com/tikitaka/naechinso/domain/recommend/dto/RecommendRequestDTO.java @@ -3,6 +3,7 @@ import com.tikitaka.naechinso.domain.member.constant.Gender; import com.tikitaka.naechinso.domain.member.entity.Member; import com.tikitaka.naechinso.global.annotation.Enum; +import io.swagger.annotations.ApiModelProperty; import lombok.*; import javax.persistence.Column; @@ -16,12 +17,15 @@ @Builder @ToString public class RecommendRequestDTO { + @ApiModelProperty(example = "닉") @NotBlank(message = "유저 이름을 입력해주세요") private String name; + @ApiModelProperty(example = "M") @Enum(enumClass = Gender.class, message = "유저의 성별 입력이 올바르지 않습니다. M 또는 W가 필요합니다") private Gender gender; + @ApiModelProperty(example = "25") @Min(value = 25, message = "25-33세까지만 추천 및 가입 가능합니다") @Max(value = 33, message = "25-33세까지만 추천 및 가입 가능합니다") private int age; @@ -44,11 +48,6 @@ public class RecommendRequestDTO { @NotNull(message = "마케팅 동의 여부가 필요합니다") private boolean acceptsMarketing; - //링크 식별을 위한 uuid - @Builder.Default - private String uuid = UUID.randomUUID().toString(); - - public Member toReceiver(String phone) { return Member.builder() .name(this.getName()) diff --git a/src/main/java/com/tikitaka/naechinso/domain/recommend/entity/Recommend.java b/src/main/java/com/tikitaka/naechinso/domain/recommend/entity/Recommend.java index 906512f..ca4fe1d 100644 --- a/src/main/java/com/tikitaka/naechinso/domain/recommend/entity/Recommend.java +++ b/src/main/java/com/tikitaka/naechinso/domain/recommend/entity/Recommend.java @@ -6,8 +6,10 @@ import com.tikitaka.naechinso.domain.recommend.dto.RecommendJoinRequestDTO; import com.tikitaka.naechinso.global.config.entity.BaseEntity; import lombok.*; +import org.hibernate.annotations.GenericGenerator; import javax.persistence.*; +import java.util.UUID; /** * 추천사 정보를 담당하는 엔티티입니다 @@ -16,6 +18,7 @@ @Entity @Table(name = "recommend") @Getter +@Setter @Builder @AllArgsConstructor @NoArgsConstructor @@ -27,6 +30,9 @@ public class Recommend extends BaseEntity { @Column(name = "rec_id") private Long id; + @Builder.Default + private String uuid = UUID.randomUUID().toString(); + /* 추천 해준 사람 */ @ManyToOne(fetch = FetchType.LAZY) @JoinColumn(name = "mem_id") @@ -82,9 +88,4 @@ public class Recommend extends BaseEntity { @Column(name = "rec_appeal") private String receiverAppeal; - public static Recommend of(RecommendJoinRequestDTO dto) { - return Recommend.builder() - .build(); - } - } diff --git a/src/main/java/com/tikitaka/naechinso/global/config/security/SecurityConfig.java b/src/main/java/com/tikitaka/naechinso/global/config/security/SecurityConfig.java index 63a0f04..a278acd 100644 --- a/src/main/java/com/tikitaka/naechinso/global/config/security/SecurityConfig.java +++ b/src/main/java/com/tikitaka/naechinso/global/config/security/SecurityConfig.java @@ -59,6 +59,7 @@ public SecurityFilterChain filterChain(HttpSecurity http) throws Exception { .antMatchers("/member/join").permitAll() .antMatchers("/sms/**").permitAll() .antMatchers("/recommend/").permitAll() + .antMatchers("/recommend/request").permitAll() .anyRequest().authenticated() .and() .headers().frameOptions().disable(); diff --git a/src/main/java/com/tikitaka/naechinso/global/error/ErrorCode.java b/src/main/java/com/tikitaka/naechinso/global/error/ErrorCode.java index 4dd7a1c..4f9ce91 100644 --- a/src/main/java/com/tikitaka/naechinso/global/error/ErrorCode.java +++ b/src/main/java/com/tikitaka/naechinso/global/error/ErrorCode.java @@ -47,6 +47,11 @@ public enum ErrorCode { USER_NOT_FOUND(NOT_FOUND, "U003","해당 유저 정보를 찾을 수 없습니다"), NOT_FOLLOW(NOT_FOUND, "U004","팔로우 중이지 않습니다"), + /* Recommend 관련 오류 */ + RECOMMEND_NOT_FOUND(NOT_FOUND, "R000","해당 추천사 정보를 찾을 수 없습니다"), + RECOMMEND_ALREADY_EXIST(BAD_REQUEST, "R001","추천사 요청은 한 번만 보낼 수 있습니다"), + CANNOT_RECOMMEND_MYSELF(BAD_REQUEST, "R002","자기 자신은 추천할 수 없습니다"), + /* Validation 오류 */ PARAMETER_NOT_VALID(BAD_REQUEST, "P000", "인자가 유효하지 않습니다"), From 8cf714fc419166463e95be7ff77b47650a1b87f1 Mon Sep 17 00:00:00 2001 From: gengminy Date: Mon, 3 Oct 2022 21:24:25 +0900 Subject: [PATCH 11/72] =?UTF-8?q?:rocket:=20feat(user):=20=ED=9A=8C?= =?UTF-8?q?=EC=9B=90=EA=B0=80=EC=9E=85=20dto=20=EC=88=98=EC=A0=95=20?= =?UTF-8?q?=EB=B0=8F=20url=20=EB=B3=80=EA=B2=BD=20#20?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../domain/member/MemberController.java | 44 ++++++--- .../domain/member/MemberService.java | 23 ++--- .../domain/member/dto/MemberDTO.java | 4 - .../domain/recommend/RecommendController.java | 54 ++++------- .../domain/recommend/RecommendRepository.java | 3 + .../domain/recommend/RecommendService.java | 95 +++++++++++++++---- .../dto/RecommendJoinRequestDTO.java | 17 ++++ .../dto/RecommendListResponseDTO.java | 13 ++- .../dto/RecommendMemberAcceptRequestDTO.java | 28 ++++++ .../recommend/dto/RecommendRequestDTO.java | 2 +- ...mendDTO.java => RecommendResponseDTO.java} | 10 +- .../sms/SmsCertificationServiceImpl.java | 21 +--- .../SmsCertificationSuccessResponseDTO.java | 6 +- .../config/security/SecurityConfig.java | 6 +- .../config/security/jwt/JwtTokenProvider.java | 15 +++ .../naechinso/global/error/ErrorCode.java | 17 ++-- 16 files changed, 224 insertions(+), 134 deletions(-) delete mode 100644 src/main/java/com/tikitaka/naechinso/domain/member/dto/MemberDTO.java create mode 100644 src/main/java/com/tikitaka/naechinso/domain/recommend/dto/RecommendMemberAcceptRequestDTO.java rename src/main/java/com/tikitaka/naechinso/domain/recommend/dto/{RecommendDTO.java => RecommendResponseDTO.java} (84%) diff --git a/src/main/java/com/tikitaka/naechinso/domain/member/MemberController.java b/src/main/java/com/tikitaka/naechinso/domain/member/MemberController.java index 1ce3835..59bc256 100644 --- a/src/main/java/com/tikitaka/naechinso/domain/member/MemberController.java +++ b/src/main/java/com/tikitaka/naechinso/domain/member/MemberController.java @@ -1,20 +1,18 @@ package com.tikitaka.naechinso.domain.member; -import com.tikitaka.naechinso.domain.member.dto.MemberCommonJoinRequestDto; -import com.tikitaka.naechinso.domain.member.dto.MemberCommonResponseDto; -import com.tikitaka.naechinso.domain.member.dto.MemberDetailJoinRequestDto; -import com.tikitaka.naechinso.domain.member.dto.MemberDetailResponseDto; +import com.tikitaka.naechinso.domain.member.dto.*; import com.tikitaka.naechinso.domain.member.entity.Member; +import com.tikitaka.naechinso.domain.recommend.RecommendService; +import com.tikitaka.naechinso.domain.recommend.dto.RecommendMemberAcceptRequestDTO; +import com.tikitaka.naechinso.domain.recommend.dto.RecommendResponseDTO; import com.tikitaka.naechinso.global.annotation.AuthMember; import com.tikitaka.naechinso.global.config.CommonApiResponse; import com.tikitaka.naechinso.global.config.security.jwt.JwtTokenProvider; import com.tikitaka.naechinso.global.error.ErrorCode; import com.tikitaka.naechinso.global.error.exception.UnauthorizedException; -import io.jsonwebtoken.Claims; import io.swagger.annotations.ApiOperation; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; -import org.apache.commons.lang3.StringUtils; import org.springframework.web.bind.annotation.*; import springfox.documentation.annotations.ApiIgnore; @@ -29,9 +27,10 @@ public class MemberController { private final MemberService memberService; + private final RecommendService recommendService; private final JwtTokenProvider jwtTokenService; - @GetMapping("/") + @GetMapping @ApiOperation(value = "유저 자신의 모든 정보를 가져온다 (AccessToken 필요)") public CommonApiResponse getMyInformation( HttpServletRequest request, @ApiIgnore @AuthMember Member member) { @@ -71,7 +70,7 @@ public CommonApiResponse getMemberDetail( } @PostMapping("/join") - @ApiOperation(value = "회원가입 세부 정보를 입력하여 최종 가입시킨다 (AccessToken 필요)") + @ApiOperation(value = "회원가입 세부 정보를 입력하여 최종 가입시킨다 (AccessToken)") public CommonApiResponse setMemberDetail( @Valid @RequestBody MemberDetailJoinRequestDto dto, @ApiIgnore @AuthMember Member member) @@ -86,17 +85,40 @@ public CommonApiResponse setMemberDetail( //페이징 처리 추가할 예정 @GetMapping("/find") - @ApiOperation(value = "현재 가입한 모든 유저를 불러온다") + @ApiOperation(value = "[Admin]현재 가입한 모든 유저를 불러온다 (AccessToken)") public CommonApiResponse> getMyInformation() { return CommonApiResponse.of(memberService.findAll()); } @PostMapping("/recommend") - @ApiOperation(value = "다른 유저의 추천사를 작성한다") - public CommonApiResponse createRecommend() { + @ApiOperation(value = "다른 유저의 추천사를 작성한다 (AccessToken)") + public CommonApiResponse createRecommend( + @RequestBody RecommendMemberAcceptRequestDTO dto, + @ApiIgnore @AuthMember Member member) + { + //로그인 상태가 아닌 경우 401 + if (member == null) { + throw new UnauthorizedException(ErrorCode.UNAUTHORIZED_USER); + } return CommonApiResponse.of(null); } + + @PatchMapping("/recommend/{uuid}/accept") + @ApiOperation(value = "요청받은 uuid 추천사에 자신을 추천인으로 등록한다 (AccessToken)") + public CommonApiResponse updateRecommendByUuid( + @PathVariable("uuid") String uuid, + @Valid @RequestBody RecommendMemberAcceptRequestDTO dto, + @ApiIgnore @AuthMember Member member) + { + //로그인 상태가 아닌 경우 401 + if (member == null) { + throw new UnauthorizedException(ErrorCode.UNAUTHORIZED_USER); + } + String phone = member.getPhone(); + RecommendResponseDTO recommendResponseDTO = recommendService.updateRecommendMemberAccept(uuid, phone, dto); + return CommonApiResponse.of(recommendResponseDTO); + } // @PostMapping("/login") diff --git a/src/main/java/com/tikitaka/naechinso/domain/member/MemberService.java b/src/main/java/com/tikitaka/naechinso/domain/member/MemberService.java index eb096d1..46bdae6 100644 --- a/src/main/java/com/tikitaka/naechinso/domain/member/MemberService.java +++ b/src/main/java/com/tikitaka/naechinso/domain/member/MemberService.java @@ -33,7 +33,6 @@ public class MemberService { private final MemberRepository memberRepository; private final MemberDetailRepository memberDetailRepository; - private final AuthenticationManagerBuilder authenticationManagerBuilder; private final JwtTokenProvider jwtTokenProvider; public List findAll() { @@ -90,24 +89,14 @@ public MemberDetailResponseDto createDetail(Member authMember, MemberDetailJoinR //영속성 유지를 위한 fetch Member member = memberRepository.findById(authMember.getId()) .orElseThrow(() -> new NotFoundException(ErrorCode.USER_NOT_FOUND)); + + //detail 정보가 있으면 이미 가입한 회원 + if (member.getDetail() != null) { + throw new BadRequestException(ErrorCode.USER_ALREADY_EXIST); + } + MemberDetail detail = MemberDetail.of(member, dto); memberDetailRepository.save(detail); return MemberDetailResponseDto.of(detail); } - -// -// public MemberCommonJoinResponseDto joinMemberWithDetail(MemberCommonJoinRequestDto dto) { -// //이미 존재하는 유저일 경우 400 -// Optional checkMember = memberRepository.findByPhone(dto.getPhone()); -// if(!checkMember.isEmpty()) { -// throw new BadRequestException(ErrorCode.USER_ALREADY_EXIST); -// } -// -// Member member = MemberCommonJoinRequestDto.toCommonMember(dto); -// memberRepository.save(member); -// -// MemberCommonJoinResponseDto res = MemberCommonJoinResponseDto.of(member); -// return res; -// } - } diff --git a/src/main/java/com/tikitaka/naechinso/domain/member/dto/MemberDTO.java b/src/main/java/com/tikitaka/naechinso/domain/member/dto/MemberDTO.java deleted file mode 100644 index dbbc0b3..0000000 --- a/src/main/java/com/tikitaka/naechinso/domain/member/dto/MemberDTO.java +++ /dev/null @@ -1,4 +0,0 @@ -package com.tikitaka.naechinso.domain.member.dto; - -public class MemberDTO { -} diff --git a/src/main/java/com/tikitaka/naechinso/domain/recommend/RecommendController.java b/src/main/java/com/tikitaka/naechinso/domain/recommend/RecommendController.java index fe806a4..13a1f63 100644 --- a/src/main/java/com/tikitaka/naechinso/domain/recommend/RecommendController.java +++ b/src/main/java/com/tikitaka/naechinso/domain/recommend/RecommendController.java @@ -27,7 +27,7 @@ public class RecommendController { private final RecommendService recommendService; private final JwtTokenProvider jwtTokenService; - @GetMapping("/") + @GetMapping @ApiOperation(value = "내 추천사 정보를 가져온다 (AccessToken 필요)") public CommonApiResponse getRecommends( @ApiIgnore @AuthMember Member member) @@ -38,22 +38,21 @@ public CommonApiResponse getRecommends( return CommonApiResponse.of(recommendService.readRecommendList(member)); } - @PostMapping("/") + @PostMapping @ApiOperation(value = "추천서를 작성한 후, 추천인을 회원가입 시킨다. (registerToken 필요)") - public CommonApiResponse createRecommendNewSender( + public CommonApiResponse createRecommendNewSender( HttpServletRequest request, @Valid @RequestBody RecommendJoinRequestDTO dto) { - String registerToken = request.getHeader("Authorization"); - String phone = parseRegisterToken(registerToken); + String phone = jwtTokenService.parsePhoneByRegisterToken(request); - RecommendDTO recommendDTO = recommendService.createRecommendJoin(phone, dto); - return CommonApiResponse.of(recommendDTO); + RecommendResponseDTO recommendResponseDTO = recommendService.createRecommendJoin(phone, dto); + return CommonApiResponse.of(recommendResponseDTO); } @GetMapping("/find") @ApiOperation(value = "[Admin]모든 추천사 정보를 가져온다 (AccessToken)") - public CommonApiResponse> getAllRecommends( + public CommonApiResponse> getAllRecommends( @ApiIgnore @AuthMember Member member) { if (member == null) { @@ -64,14 +63,13 @@ public CommonApiResponse> getAllRecommends( @PostMapping("/request") @ApiOperation(value = "다른 유저에게 추천서 작성을 요청한다 (registerToken 필요)") - public CommonApiResponse createRecommendRequest( + public CommonApiResponse createRecommendRequest( HttpServletRequest request, @Valid @RequestBody RecommendRequestDTO dto) { - String registerToken = request.getHeader("Authorization"); - String phone = parseRegisterToken(registerToken); - RecommendDTO recommendDTO = recommendService.createRecommendRequest(phone, dto); - return CommonApiResponse.of(recommendDTO); + String phone = jwtTokenService.parsePhoneByRegisterToken(request); + RecommendResponseDTO recommendResponseDTO = recommendService.createRecommendRequest(phone, dto); + return CommonApiResponse.of(recommendResponseDTO); } @@ -83,38 +81,28 @@ public CommonApiResponse createRecommendRequest( //제일 아래에 있어야함 @GetMapping("/{uuid}") @ApiOperation(value = "추천 요청받은 uuid 를 가진 추천사 정보를 가져온다 (Register / AccessToken 필요)") - public CommonApiResponse getRecommendByUuid( + public CommonApiResponse getRecommendByUuid( HttpServletRequest request, @PathVariable("uuid") String uuid) { //토큰 장착 확인 - String token = request.getHeader("Authorization"); - String phone = parseRegisterToken(token); + String phone = jwtTokenService.parsePhoneByRegisterToken(request); - RecommendDTO recommendDTO = RecommendDTO.of(recommendService.findByUuid(uuid)); - return CommonApiResponse.of(recommendDTO); + RecommendResponseDTO recommendResponseDTO = RecommendResponseDTO.of(recommendService.findByUuid(uuid)); + return CommonApiResponse.of(recommendResponseDTO); } - @PatchMapping("/{uuid}") - @ApiOperation(value = "요청받은 uuid 추천사에 자신을 추천인으로 등록한다 (Register / AccessToken 필요)") - public CommonApiResponse getRecommendByUuid( + @PatchMapping("/{uuid}/accept") + @ApiOperation(value = "요청받은 uuid 추천사에 자신을 추천인으로 등록한다 (Register 필요)") + public CommonApiResponse updateRecommendByUuid( HttpServletRequest request, @PathVariable("uuid") String uuid, @Valid @RequestBody RecommendAcceptRequestDTO dto) { //토큰 장착 확인 - String token = request.getHeader("Authorization"); - String phone = parseRegisterToken(token); + String phone = jwtTokenService.parsePhoneByRegisterToken(request); - RecommendDTO recommendDTO = recommendService.updateRecommendRequest(uuid, phone, dto); - return CommonApiResponse.of(recommendDTO); + RecommendResponseDTO recommendResponseDTO = recommendService.updateRecommendRequest(uuid, phone, dto); + return CommonApiResponse.of(recommendResponseDTO); } - - private String parseRegisterToken(String registerToken) { - if (StringUtils.isBlank(registerToken) || !jwtTokenService.validateToken(registerToken)) { - throw new UnauthorizedException(ErrorCode.NO_TOKEN); - } - return jwtTokenService.parseClaims(registerToken).getSubject(); - } - } diff --git a/src/main/java/com/tikitaka/naechinso/domain/recommend/RecommendRepository.java b/src/main/java/com/tikitaka/naechinso/domain/recommend/RecommendRepository.java index a0c2ae7..0d267d0 100644 --- a/src/main/java/com/tikitaka/naechinso/domain/recommend/RecommendRepository.java +++ b/src/main/java/com/tikitaka/naechinso/domain/recommend/RecommendRepository.java @@ -20,6 +20,9 @@ public interface RecommendRepository extends JpaRepository { List findAllByIdNotNull(); Optional findByUuid(String uuid); + Optional findByUuidAndReceiverNotNull(String uuid); Boolean existsByReceiverPhone(String phone); + + Boolean existsByReceiverPhoneAndSenderNotNull(String phone); } diff --git a/src/main/java/com/tikitaka/naechinso/domain/recommend/RecommendService.java b/src/main/java/com/tikitaka/naechinso/domain/recommend/RecommendService.java index 975a2b1..1ef7276 100644 --- a/src/main/java/com/tikitaka/naechinso/domain/recommend/RecommendService.java +++ b/src/main/java/com/tikitaka/naechinso/domain/recommend/RecommendService.java @@ -1,6 +1,7 @@ package com.tikitaka.naechinso.domain.recommend; import com.tikitaka.naechinso.domain.member.MemberRepository; +import com.tikitaka.naechinso.domain.recommend.dto.RecommendMemberAcceptRequestDTO; import com.tikitaka.naechinso.domain.member.entity.Member; import com.tikitaka.naechinso.domain.recommend.dto.*; import com.tikitaka.naechinso.domain.recommend.entity.Recommend; @@ -14,7 +15,6 @@ import java.util.ArrayList; import java.util.List; import java.util.Optional; -import java.util.UUID; @Service @RequiredArgsConstructor @@ -30,7 +30,12 @@ public RecommendListResponseDTO readRecommendList(Member authMember) { return RecommendListResponseDTO.of(member); } - public RecommendDTO createRecommendJoin(String senderPhone, RecommendJoinRequestDTO dto) { + public RecommendResponseDTO createRecommend(String senderPhone, RecommendResponseDTO dto) { + + return null; + } + + public RecommendResponseDTO createRecommendJoin(String senderPhone, RecommendJoinRequestDTO dto) { //멤버가 이미 있으면 종료 Optional checkSender = memberRepository.findByPhone(senderPhone); if (checkSender.isPresent()) { @@ -69,10 +74,10 @@ public RecommendDTO createRecommendJoin(String senderPhone, RecommendJoinRequest memberRepository.save(sender); recommendRepository.save(recommend); - return RecommendDTO.of(recommend); + return RecommendResponseDTO.of(recommend); } - public RecommendDTO createRecommendRequest(String receiverPhone, RecommendRequestDTO dto) { + public RecommendResponseDTO createRecommendRequest(String receiverPhone, RecommendRequestDTO dto) { //이미 추천사 요청을 보냄 if (existsByReceiverPhone(receiverPhone)) { throw(new NotFoundException(ErrorCode.RECOMMEND_ALREADY_EXIST)); @@ -91,19 +96,24 @@ public RecommendDTO createRecommendRequest(String receiverPhone, RecommendReques memberRepository.save(receiver); recommendRepository.save(recommend); - return RecommendDTO.of(recommend); + return RecommendResponseDTO.of(recommend); } - public RecommendDTO updateRecommendRequest(String uuid, String senderPhone, RecommendAcceptRequestDTO dto) { + public RecommendResponseDTO updateRecommendRequest(String uuid, String senderPhone, RecommendAcceptRequestDTO dto) { - Recommend recommend = findByUuid(uuid); + Recommend recommend = findByUuidAndReceiverNotNull(uuid); //자기 자신을 추천하면 종료 - if (senderPhone == recommend.getReceiverPhone()) { + if (senderPhone.equals(recommend.getReceiverPhone())) { throw new BadRequestException(ErrorCode.CANNOT_RECOMMEND_MYSELF); } - //유저가 없으면 회원가입 시킴 있으면 그대로 사용 + //이미 작성된 추천사 엔티티면 종료 + if (recommend.getSender() != null) { + throw new BadRequestException(ErrorCode.RECOMMEND_SENDER_ALREADY_EXIST); + } + + //유저가 없으면 회원가입 시킴, 있으면 그대로 사용 Member sender = memberRepository.findByPhone(senderPhone) .orElse(dto.toSender(senderPhone)); @@ -125,30 +135,69 @@ public RecommendDTO updateRecommendRequest(String uuid, String senderPhone, Reco memberRepository.save(sender); recommendRepository.save(recommend); - return RecommendDTO.of(recommend); + return RecommendResponseDTO.of(recommend); } + /** + * 추천사 작성 유저가 정회원일 경우 유저 정보로 추천사를 등록한다 + * + * */ + public RecommendResponseDTO updateRecommendMemberAccept(String uuid, String senderPhone, RecommendMemberAcceptRequestDTO dto) { + + Recommend recommend = findByUuidAndReceiverNotNull(uuid); + + //자기 자신을 추천하면 종료 + if (senderPhone.equals(recommend.getReceiverPhone())) { + throw new BadRequestException(ErrorCode.CANNOT_RECOMMEND_MYSELF); + } - public List findAll() { - List recommendDTOList = new ArrayList<>(); + //이미 작성된 추천사 엔티티면 종료 + if (recommend.getSender() != null) { + throw new BadRequestException(ErrorCode.RECOMMEND_SENDER_ALREADY_EXIST); + } + + //유저가 없으면 400 + Member sender = memberRepository.findByPhone(senderPhone) + .orElseThrow(() -> new BadRequestException(ErrorCode.USER_NOT_FOUND)); + + recommend.setSender(sender); + recommend.setSenderPhone(sender.getPhone()); + recommend.setSenderName(sender.getName()); + recommend.setSenderAge(sender.getAge()); + recommend.setSenderGender(sender.getGender()); + recommend.setSenderJobName(sender.getJobName()); + recommend.setSenderJobPart(sender.getJobPart()); + recommend.setSenderJobLocation(sender.getJobLocation()); + recommend.setReceiverAppeal(dto.getAppeal()); + recommend.setReceiverMeet(dto.getMeet()); + recommend.setReceiverPersonality(dto.getPersonality()); + + memberRepository.save(sender); + recommendRepository.save(recommend); + + return RecommendResponseDTO.of(recommend); + } + + public List findAll() { + List recommendResponseDTOList = new ArrayList<>(); recommendRepository.findAllByIdNotNull().forEach( - recommend -> recommendDTOList.add(RecommendDTO.of(recommend)) + recommend -> recommendResponseDTOList.add(RecommendResponseDTO.of(recommend)) ); - recommendDTOList.forEach( + recommendResponseDTOList.forEach( recommendDTO -> System.out.println("recommendDTO = " + recommendDTO) ); - return recommendDTOList; + return recommendResponseDTOList; } - public List findAllBySenderPhone(String phone) { - List recommendDTOList = new ArrayList<>(); + public List findAllBySenderPhone(String phone) { + List recommendResponseDTOList = new ArrayList<>(); recommendRepository.findAllBySenderPhone(phone).stream().map( - recommend -> recommendDTOList.add(RecommendDTO.of(recommend)) + recommend -> recommendResponseDTOList.add(RecommendResponseDTO.of(recommend)) ); - return recommendDTOList; + return recommendResponseDTOList; } public Recommend findByUuid(String uuid) { @@ -156,8 +205,16 @@ public Recommend findByUuid(String uuid) { .orElseThrow(() -> new NotFoundException(ErrorCode.RECOMMEND_NOT_FOUND)); } + public Recommend findByUuidAndReceiverNotNull(String uuid) { + return recommendRepository.findByUuidAndReceiverNotNull(uuid) + .orElseThrow(() -> new NotFoundException(ErrorCode.RECOMMEND_RECEIVER_NOT_EXIST)); + } + public Boolean existsByReceiverPhone(String phone){ return recommendRepository.existsByReceiverPhone(phone); } + public Boolean existsByReceiverPhoneAndSenderNotNull(String phone){ + return recommendRepository.existsByReceiverPhoneAndSenderNotNull(phone); + } } diff --git a/src/main/java/com/tikitaka/naechinso/domain/recommend/dto/RecommendJoinRequestDTO.java b/src/main/java/com/tikitaka/naechinso/domain/recommend/dto/RecommendJoinRequestDTO.java index 50a1c9c..5d294df 100644 --- a/src/main/java/com/tikitaka/naechinso/domain/recommend/dto/RecommendJoinRequestDTO.java +++ b/src/main/java/com/tikitaka/naechinso/domain/recommend/dto/RecommendJoinRequestDTO.java @@ -109,4 +109,21 @@ public Member toSender(String phone){ .jobLocation(this.jobLocation) .build(); } + + public Member toReceiver(String phone){ + return Member.builder() + .phone(phone) + .name(this.name) + .gender(this.gender) + .age(this.age) + .acceptsService(this.acceptsService) + .acceptsInfo(this.acceptsInfo) + .acceptsReligion(this.acceptsReligion) + .acceptsLocation(this.acceptsLocation) + .acceptsMarketing(this.acceptsMarketing) + .jobName(this.jobName) + .jobPart(this.jobPart) + .jobLocation(this.jobLocation) + .build(); + } } diff --git a/src/main/java/com/tikitaka/naechinso/domain/recommend/dto/RecommendListResponseDTO.java b/src/main/java/com/tikitaka/naechinso/domain/recommend/dto/RecommendListResponseDTO.java index ff98099..bbc1a53 100644 --- a/src/main/java/com/tikitaka/naechinso/domain/recommend/dto/RecommendListResponseDTO.java +++ b/src/main/java/com/tikitaka/naechinso/domain/recommend/dto/RecommendListResponseDTO.java @@ -1,7 +1,6 @@ package com.tikitaka.naechinso.domain.recommend.dto; import com.tikitaka.naechinso.domain.member.entity.Member; -import com.tikitaka.naechinso.domain.recommend.entity.Recommend; import lombok.*; import java.util.ArrayList; @@ -13,20 +12,20 @@ @Builder @ToString public class RecommendListResponseDTO { - List recommend = new ArrayList<>(); - List recommendReceived = new ArrayList<>(); + List recommend = new ArrayList<>(); + List recommendReceived = new ArrayList<>(); public static RecommendListResponseDTO of(Member member) { - List recommendList = new ArrayList<>(); - List recommendReceivedList = new ArrayList<>(); + List recommendList = new ArrayList<>(); + List recommendReceivedList = new ArrayList<>(); member.getRecommends().stream().forEach(recommend -> - recommendList.add(RecommendDTO.of(recommend)) + recommendList.add(RecommendResponseDTO.of(recommend)) ); member.getRecommend_received().stream().forEach(recommend -> - recommendReceivedList.add(RecommendDTO.of(recommend)) + recommendReceivedList.add(RecommendResponseDTO.of(recommend)) ); return RecommendListResponseDTO.builder() diff --git a/src/main/java/com/tikitaka/naechinso/domain/recommend/dto/RecommendMemberAcceptRequestDTO.java b/src/main/java/com/tikitaka/naechinso/domain/recommend/dto/RecommendMemberAcceptRequestDTO.java new file mode 100644 index 0000000..31a6d08 --- /dev/null +++ b/src/main/java/com/tikitaka/naechinso/domain/recommend/dto/RecommendMemberAcceptRequestDTO.java @@ -0,0 +1,28 @@ +package com.tikitaka.naechinso.domain.recommend.dto; + +import io.swagger.annotations.ApiModelProperty; +import lombok.*; + +import javax.validation.constraints.*; + +/** 내친소 회원이 다른 유저를 추천할 때 사용할 DTO + * @author gengminy 221003 + */ +@AllArgsConstructor +@NoArgsConstructor +@Getter +@Builder +@ToString +public class RecommendMemberAcceptRequestDTO { + @ApiModelProperty(example = "CMC 에서") + @NotBlank(message = "만나게 된 계기를 입력해주세요") + private String meet; + + @ApiModelProperty(example = "최고") + @NotBlank(message = "친구의 성격 키워드를 입력해주세요") + private String personality; + + @ApiModelProperty(example = "짱") + @NotBlank(message = "친구의 매력을 입력해주세요") + private String appeal; +} diff --git a/src/main/java/com/tikitaka/naechinso/domain/recommend/dto/RecommendRequestDTO.java b/src/main/java/com/tikitaka/naechinso/domain/recommend/dto/RecommendRequestDTO.java index cc132e3..c3e5825 100644 --- a/src/main/java/com/tikitaka/naechinso/domain/recommend/dto/RecommendRequestDTO.java +++ b/src/main/java/com/tikitaka/naechinso/domain/recommend/dto/RecommendRequestDTO.java @@ -50,8 +50,8 @@ public class RecommendRequestDTO { public Member toReceiver(String phone) { return Member.builder() - .name(this.getName()) .name(this.name) + .phone(phone) .gender(this.gender) .age(this.age) .acceptsService(this.acceptsService) diff --git a/src/main/java/com/tikitaka/naechinso/domain/recommend/dto/RecommendDTO.java b/src/main/java/com/tikitaka/naechinso/domain/recommend/dto/RecommendResponseDTO.java similarity index 84% rename from src/main/java/com/tikitaka/naechinso/domain/recommend/dto/RecommendDTO.java rename to src/main/java/com/tikitaka/naechinso/domain/recommend/dto/RecommendResponseDTO.java index 5ad551b..a5189e6 100644 --- a/src/main/java/com/tikitaka/naechinso/domain/recommend/dto/RecommendDTO.java +++ b/src/main/java/com/tikitaka/naechinso/domain/recommend/dto/RecommendResponseDTO.java @@ -1,19 +1,15 @@ package com.tikitaka.naechinso.domain.recommend.dto; import com.tikitaka.naechinso.domain.member.constant.Gender; -import com.tikitaka.naechinso.domain.member.entity.Member; import com.tikitaka.naechinso.domain.recommend.entity.Recommend; import lombok.*; -import javax.persistence.*; -import java.util.UUID; - @AllArgsConstructor @NoArgsConstructor @Getter @Builder @ToString -public class RecommendDTO { +public class RecommendResponseDTO { private String uuid; @@ -32,7 +28,7 @@ public class RecommendDTO { private Long receiverId; - public static RecommendDTO of(Recommend recommend) { + public static RecommendResponseDTO of(Recommend recommend) { Long senderId; Long receiverId; if (recommend.getSender() == null) { @@ -47,7 +43,7 @@ public static RecommendDTO of(Recommend recommend) { receiverId = recommend.getReceiver().getId(); } - return RecommendDTO.builder() + return RecommendResponseDTO.builder() .uuid(recommend.getUuid()) .phone(recommend.getReceiverPhone()) .senderId(senderId) diff --git a/src/main/java/com/tikitaka/naechinso/domain/sms/SmsCertificationServiceImpl.java b/src/main/java/com/tikitaka/naechinso/domain/sms/SmsCertificationServiceImpl.java index b2dbdf3..d68a5b5 100644 --- a/src/main/java/com/tikitaka/naechinso/domain/sms/SmsCertificationServiceImpl.java +++ b/src/main/java/com/tikitaka/naechinso/domain/sms/SmsCertificationServiceImpl.java @@ -1,13 +1,9 @@ package com.tikitaka.naechinso.domain.sms; -import com.fasterxml.jackson.databind.ObjectMapper; import com.tikitaka.naechinso.domain.member.MemberRepository; -import com.tikitaka.naechinso.domain.member.MemberService; import com.tikitaka.naechinso.domain.member.entity.Member; -import com.tikitaka.naechinso.domain.recommend.RecommendRepository; import com.tikitaka.naechinso.domain.recommend.RecommendService; -import com.tikitaka.naechinso.domain.recommend.dto.RecommendDTO; -import com.tikitaka.naechinso.domain.recommend.dto.RecommendListResponseDTO; +import com.tikitaka.naechinso.domain.recommend.dto.RecommendResponseDTO; import com.tikitaka.naechinso.domain.sms.dto.SmsCertificationSuccessResponseDTO; import com.tikitaka.naechinso.global.common.response.TokenResponseDTO; import com.tikitaka.naechinso.global.config.security.dto.JwtDTO; @@ -15,26 +11,16 @@ import com.tikitaka.naechinso.global.error.ErrorCode; import com.tikitaka.naechinso.global.error.exception.InternalServerException; import com.tikitaka.naechinso.infra.sms.SmsService; -import com.tikitaka.naechinso.infra.sms.dto.NaverSmsMessageDTO; -import com.tikitaka.naechinso.infra.sms.dto.NaverSmsRequestDTO; import com.tikitaka.naechinso.domain.sms.dto.SmsCertificationRequestDTO; -import com.tikitaka.naechinso.infra.sms.dto.NaverSmsResponseDTO; import com.tikitaka.naechinso.global.error.exception.BadRequestException; import com.tikitaka.naechinso.global.error.exception.UnauthorizedException; import com.tikitaka.naechinso.global.config.redis.RedisService; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; -import org.apache.tomcat.util.codec.binary.Base64; import org.springframework.beans.factory.annotation.Value; -import org.springframework.http.MediaType; import org.springframework.stereotype.Service; -import org.springframework.web.reactive.function.BodyInserters; -import org.springframework.web.reactive.function.client.WebClient; -import javax.crypto.Mac; -import javax.crypto.spec.SecretKeySpec; import java.time.Duration; -import java.util.ArrayList; import java.util.List; import java.util.Optional; import java.util.Random; @@ -119,8 +105,7 @@ public SmsCertificationSuccessResponseDTO verifyCode(SmsCertificationRequestDTO redisService.deleteValues(key); //추천 받은 정보가 있는지 - Boolean recommendReceived = recommendService.existsByReceiverPhone(phoneNumber); - List recommendDTOList = recommendService.findAllBySenderPhone(phoneNumber); + Boolean recommendReceived = recommendService.existsByReceiverPhoneAndSenderNotNull(phoneNumber); //가입 안된 회원일 경우 registerToken 리턴 Optional checkMember = memberRepository.findByPhone(phoneNumber); @@ -129,7 +114,6 @@ public SmsCertificationSuccessResponseDTO verifyCode(SmsCertificationRequestDTO return SmsCertificationSuccessResponseDTO.builder() .registerToken(registerToken) - .recommendRequests(recommendDTOList) .recommendReceived(recommendReceived) .build(); } @@ -143,7 +127,6 @@ public SmsCertificationSuccessResponseDTO verifyCode(SmsCertificationRequestDTO return SmsCertificationSuccessResponseDTO.builder() .accessToken(tokenResponseDTO.getAccessToken()) .refreshToken(tokenResponseDTO.getRefreshToken()) - .recommendRequests(recommendDTOList) .recommendReceived(recommendReceived) .build(); } catch (Exception e) { diff --git a/src/main/java/com/tikitaka/naechinso/domain/sms/dto/SmsCertificationSuccessResponseDTO.java b/src/main/java/com/tikitaka/naechinso/domain/sms/dto/SmsCertificationSuccessResponseDTO.java index 501a78e..6df139e 100644 --- a/src/main/java/com/tikitaka/naechinso/domain/sms/dto/SmsCertificationSuccessResponseDTO.java +++ b/src/main/java/com/tikitaka/naechinso/domain/sms/dto/SmsCertificationSuccessResponseDTO.java @@ -1,7 +1,7 @@ package com.tikitaka.naechinso.domain.sms.dto; import com.fasterxml.jackson.annotation.JsonInclude; -import com.tikitaka.naechinso.domain.recommend.dto.RecommendDTO; +import com.tikitaka.naechinso.domain.recommend.dto.RecommendResponseDTO; import lombok.*; import java.util.ArrayList; @@ -18,10 +18,6 @@ public class SmsCertificationSuccessResponseDTO { private String refreshToken; private String registerToken; - //receiver 는 있지만 sender 는 없는 Recommend 를 가져옴 (추천 요청) - @Builder.Default - private List recommendRequests = new ArrayList<>(); - //추천 받았는지 여부, true 면 유효한 유저 private Boolean recommendReceived = false; } diff --git a/src/main/java/com/tikitaka/naechinso/global/config/security/SecurityConfig.java b/src/main/java/com/tikitaka/naechinso/global/config/security/SecurityConfig.java index a278acd..f9a388c 100644 --- a/src/main/java/com/tikitaka/naechinso/global/config/security/SecurityConfig.java +++ b/src/main/java/com/tikitaka/naechinso/global/config/security/SecurityConfig.java @@ -7,6 +7,7 @@ import lombok.RequiredArgsConstructor; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; +import org.springframework.http.HttpMethod; import org.springframework.security.config.annotation.web.builders.HttpSecurity; import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity; import org.springframework.security.config.http.SessionCreationPolicy; @@ -18,6 +19,8 @@ import org.springframework.web.cors.CorsUtils; import org.springframework.web.cors.UrlBasedCorsConfigurationSource; +import javax.servlet.http.HttpServlet; + /** 인증 및 Security 관련 설정 클래스입니다 * @author gengminy (220919) */ @EnableWebSecurity @@ -58,7 +61,8 @@ public SecurityFilterChain filterChain(HttpSecurity http) throws Exception { .antMatchers("/member/login").permitAll() .antMatchers("/member/join").permitAll() .antMatchers("/sms/**").permitAll() - .antMatchers("/recommend/").permitAll() + .antMatchers(HttpMethod.POST, "/recommend").permitAll() + .antMatchers("/recommend/**").permitAll() .antMatchers("/recommend/request").permitAll() .anyRequest().authenticated() .and() diff --git a/src/main/java/com/tikitaka/naechinso/global/config/security/jwt/JwtTokenProvider.java b/src/main/java/com/tikitaka/naechinso/global/config/security/jwt/JwtTokenProvider.java index 4d48ae1..2c4b60b 100644 --- a/src/main/java/com/tikitaka/naechinso/global/config/security/jwt/JwtTokenProvider.java +++ b/src/main/java/com/tikitaka/naechinso/global/config/security/jwt/JwtTokenProvider.java @@ -10,6 +10,7 @@ import io.jsonwebtoken.*; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; +import org.apache.commons.lang3.StringUtils; import org.springframework.beans.factory.annotation.Value; import org.springframework.security.authentication.UsernamePasswordAuthenticationToken; import org.springframework.security.core.Authentication; @@ -199,6 +200,20 @@ public void validateRefreshToken(String userId, String refreshToken) { } } + /** + * Request Header 에서 RegisterToken 파싱 및 phone 추출 + * @param request Auth Token 장착한 Request + * @return phone 휴대폰 + * */ + public String parsePhoneByRegisterToken(HttpServletRequest request) { + String registerToken = request.getHeader("Authorization"); + if (StringUtils.isBlank(registerToken) || !validateToken(registerToken)) { + throw new UnauthorizedException(ErrorCode.NO_TOKEN); + } + return parseClaims(registerToken).getSubject(); + } + + /** * JWT 토큰에서 claims 추출 * @param accessToken 추출하고 싶은 AccessToken (JWT) diff --git a/src/main/java/com/tikitaka/naechinso/global/error/ErrorCode.java b/src/main/java/com/tikitaka/naechinso/global/error/ErrorCode.java index 4f9ce91..ad1672d 100644 --- a/src/main/java/com/tikitaka/naechinso/global/error/ErrorCode.java +++ b/src/main/java/com/tikitaka/naechinso/global/error/ErrorCode.java @@ -20,13 +20,13 @@ public enum ErrorCode { /* Auth 관련 오류 */ - NO_TOKEN(BAD_REQUEST, "AUTH000", "토큰이 존재하지 않습니다"), - EXPIRED_TOKEN(BAD_REQUEST, "AUTH001", "만료된 엑세스 토큰입니다"), - INVALID_REFRESH_TOKEN(BAD_REQUEST, "AUTH002", "리프레시 토큰이 유효하지 않습니다"), - MISMATCH_REFRESH_TOKEN(BAD_REQUEST, "AUTH003", "리프레시 토큰의 유저 정보가 일치하지 않습니다"), + NO_TOKEN(UNAUTHORIZED, "AUTH000", "토큰이 존재하지 않습니다"), + EXPIRED_TOKEN(UNAUTHORIZED, "AUTH001", "만료된 엑세스 토큰입니다"), + INVALID_REFRESH_TOKEN(UNAUTHORIZED, "AUTH002", "리프레시 토큰이 유효하지 않습니다"), + MISMATCH_REFRESH_TOKEN(UNAUTHORIZED, "AUTH003", "리프레시 토큰의 유저 정보가 일치하지 않습니다"), INVALID_AUTH_TOKEN(UNAUTHORIZED, "AUTH004", "권한 정보가 없는 토큰입니다"), UNAUTHORIZED_USER(UNAUTHORIZED, "AUTH005", "로그인이 필요합니다"), - REFRESH_TOKEN_NOT_FOUND(NOT_FOUND, "AUTH006", "로그아웃 된 사용자입니다"), + REFRESH_TOKEN_NOT_FOUND(UNAUTHORIZED, "AUTH006", "로그아웃 된 사용자입니다"), FORBIDDEN_USER(FORBIDDEN, "AUTH007", "권한이 없는 유저입니다"), UNSUPPORTED_TOKEN(UNAUTHORIZED, "AUTH008", "지원하지 않는 토큰입니다"), INVALID_SIGNATURE(UNAUTHORIZED, "AUTH009", "잘못된 JWT 서명입니다"), @@ -35,11 +35,6 @@ public enum ErrorCode { LOGIN_FAILED(UNAUTHORIZED, "AUTH012", "로그인에 실패했습니다"), - /* OAuth 관련 오류 */ - KAKAO_BAD_REQUEST(BAD_REQUEST, "OAUTH001", "카카오 토큰 오류"), - KAKAO_USER_NOT_FOUND(BAD_REQUEST, "OAUTH002", "카카오 유저를 찾을 수 없습니다"), - KAKAO_USER_EMAIL_NOT_FOUND(BAD_REQUEST, "OAUTH003", "이메일 동의를 하지 않았습니다"), - /* User 관련 오류 */ CANNOT_FOLLOW_MYSELF(BAD_REQUEST, "U001", "자기 자신은 팔로우 할 수 없습니다"), @@ -51,6 +46,8 @@ public enum ErrorCode { RECOMMEND_NOT_FOUND(NOT_FOUND, "R000","해당 추천사 정보를 찾을 수 없습니다"), RECOMMEND_ALREADY_EXIST(BAD_REQUEST, "R001","추천사 요청은 한 번만 보낼 수 있습니다"), CANNOT_RECOMMEND_MYSELF(BAD_REQUEST, "R002","자기 자신은 추천할 수 없습니다"), + RECOMMEND_SENDER_ALREADY_EXIST(BAD_REQUEST, "R003","유저 추천사는 한 번만 작성할 수 있습니다"), + RECOMMEND_RECEIVER_NOT_EXIST(BAD_REQUEST, "R004","추천 받을 사람이 존재하지 않습니다"), /* Validation 오류 */ PARAMETER_NOT_VALID(BAD_REQUEST, "P000", "인자가 유효하지 않습니다"), From 3c62ba43100db63c520ae3107a7f9d25855f038b Mon Sep 17 00:00:00 2001 From: gengminy Date: Wed, 5 Oct 2022 16:35:44 +0900 Subject: [PATCH 12/72] =?UTF-8?q?:hammer:=20fix(user):=20=EC=98=88?= =?UTF-8?q?=EC=99=B8=20=EC=97=90=EB=9F=AC=EC=BD=94=EB=93=9C=20=EC=B6=94?= =?UTF-8?q?=EA=B0=80=20#20?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../domain/member/MemberController.java | 12 +- .../domain/recommend/RecommendController.java | 2 +- .../domain/recommend/RecommendService.java | 1 + .../sms/SmsCertificationServiceImpl.java | 2 +- .../naechinso/global/error/ErrorCode.java | 1 + .../naechinso/NaechinsoApplicationTests.java | 2 +- .../SmsCertificationControllerTest.java | 111 +++++----- .../service/SmsCertificationServiceTest.java | 189 ++++++++++++++++++ src/test/resources/application.yml | 29 ++- 9 files changed, 262 insertions(+), 87 deletions(-) create mode 100644 src/test/java/com/tikitaka/naechinso/unit/service/SmsCertificationServiceTest.java diff --git a/src/main/java/com/tikitaka/naechinso/domain/member/MemberController.java b/src/main/java/com/tikitaka/naechinso/domain/member/MemberController.java index 59bc256..888d235 100644 --- a/src/main/java/com/tikitaka/naechinso/domain/member/MemberController.java +++ b/src/main/java/com/tikitaka/naechinso/domain/member/MemberController.java @@ -115,17 +115,11 @@ public CommonApiResponse updateRecommendByUuid( if (member == null) { throw new UnauthorizedException(ErrorCode.UNAUTHORIZED_USER); } + if (member.getDetail() == null) { + throw new UnauthorizedException(ErrorCode.FORBIDDEN_USER); + } String phone = member.getPhone(); RecommendResponseDTO recommendResponseDTO = recommendService.updateRecommendMemberAccept(uuid, phone, dto); return CommonApiResponse.of(recommendResponseDTO); } -// @PostMapping("/login") - - -// @GetMapping("/find") -// public CommonApiResponse findAllMember() { -// final String a = memberService.getMember(); -// return CommonApiResponse.of(a); -// } - } diff --git a/src/main/java/com/tikitaka/naechinso/domain/recommend/RecommendController.java b/src/main/java/com/tikitaka/naechinso/domain/recommend/RecommendController.java index 13a1f63..067fd89 100644 --- a/src/main/java/com/tikitaka/naechinso/domain/recommend/RecommendController.java +++ b/src/main/java/com/tikitaka/naechinso/domain/recommend/RecommendController.java @@ -93,7 +93,7 @@ public CommonApiResponse getRecommendByUuid( } @PatchMapping("/{uuid}/accept") - @ApiOperation(value = "요청받은 uuid 추천사에 자신을 추천인으로 등록한다 (Register 필요)") + @ApiOperation(value = "요청받은 uuid 추천사에 자신을 추천인으로 등록한 후 임시 회원으로 가입한다 (Register 필요)") public CommonApiResponse updateRecommendByUuid( HttpServletRequest request, @PathVariable("uuid") String uuid, diff --git a/src/main/java/com/tikitaka/naechinso/domain/recommend/RecommendService.java b/src/main/java/com/tikitaka/naechinso/domain/recommend/RecommendService.java index 1ef7276..ee17f03 100644 --- a/src/main/java/com/tikitaka/naechinso/domain/recommend/RecommendService.java +++ b/src/main/java/com/tikitaka/naechinso/domain/recommend/RecommendService.java @@ -217,4 +217,5 @@ public Boolean existsByReceiverPhone(String phone){ public Boolean existsByReceiverPhoneAndSenderNotNull(String phone){ return recommendRepository.existsByReceiverPhoneAndSenderNotNull(phone); } + } diff --git a/src/main/java/com/tikitaka/naechinso/domain/sms/SmsCertificationServiceImpl.java b/src/main/java/com/tikitaka/naechinso/domain/sms/SmsCertificationServiceImpl.java index d68a5b5..c405945 100644 --- a/src/main/java/com/tikitaka/naechinso/domain/sms/SmsCertificationServiceImpl.java +++ b/src/main/java/com/tikitaka/naechinso/domain/sms/SmsCertificationServiceImpl.java @@ -54,7 +54,7 @@ public String sendVerificationMessage(String to) { final Duration verificationTimeLimit = Duration.ofSeconds(VERIFICATION_TIME_LIMIT); //[local, dev] 배포 환경이 아닐때는 fake service 를 제공합니다 - if (!springProfile.equals("prod")) { + if (springProfile == null || !springProfile.equals("prod")) { log.info("스프링 프로파일(" + springProfile + ") 따라 fake 서비스를 제공합니다"); String message = generateMessageWithCode(verificationCode); log.info(message); diff --git a/src/main/java/com/tikitaka/naechinso/global/error/ErrorCode.java b/src/main/java/com/tikitaka/naechinso/global/error/ErrorCode.java index ad1672d..cc7d739 100644 --- a/src/main/java/com/tikitaka/naechinso/global/error/ErrorCode.java +++ b/src/main/java/com/tikitaka/naechinso/global/error/ErrorCode.java @@ -42,6 +42,7 @@ public enum ErrorCode { USER_NOT_FOUND(NOT_FOUND, "U003","해당 유저 정보를 찾을 수 없습니다"), NOT_FOLLOW(NOT_FOUND, "U004","팔로우 중이지 않습니다"), + /* Recommend 관련 오류 */ RECOMMEND_NOT_FOUND(NOT_FOUND, "R000","해당 추천사 정보를 찾을 수 없습니다"), RECOMMEND_ALREADY_EXIST(BAD_REQUEST, "R001","추천사 요청은 한 번만 보낼 수 있습니다"), diff --git a/src/test/java/com/tikitaka/naechinso/NaechinsoApplicationTests.java b/src/test/java/com/tikitaka/naechinso/NaechinsoApplicationTests.java index c1be908..5d09e46 100644 --- a/src/test/java/com/tikitaka/naechinso/NaechinsoApplicationTests.java +++ b/src/test/java/com/tikitaka/naechinso/NaechinsoApplicationTests.java @@ -10,7 +10,7 @@ @SpringBootTest @RunWith(SpringRunner.class) @ActiveProfiles("local") -@TestPropertySource(locations="classpath:test.yml") +@TestPropertySource(locations="classpath:application.yml") class NaechinsoApplicationTests { } diff --git a/src/test/java/com/tikitaka/naechinso/unit/controller/SmsCertificationControllerTest.java b/src/test/java/com/tikitaka/naechinso/unit/controller/SmsCertificationControllerTest.java index 27e431a..f1e8261 100644 --- a/src/test/java/com/tikitaka/naechinso/unit/controller/SmsCertificationControllerTest.java +++ b/src/test/java/com/tikitaka/naechinso/unit/controller/SmsCertificationControllerTest.java @@ -1,58 +1,53 @@ -//package com.tikitaka.naechinso.unit.controller; -// -//import com.tikitaka.naechinso.domain.sms.SmsCertificationController; -//import com.tikitaka.naechinso.domain.sms.dto.SmsVerificationCodeRequestDTO; -//import com.tikitaka.naechinso.global.config.redis.RedisService; -//import com.tikitaka.naechinso.domain.sms.SmsCertificationService; -//import com.tikitaka.naechinso.domain.sms.SmsCertificationServiceImpl; -//import org.hibernate.service.spi.InjectService; -//import org.junit.jupiter.api.Assertions; -//import org.junit.jupiter.api.DisplayName; -//import org.junit.jupiter.api.Test; -//import org.mockito.InjectMocks; -//import org.mockito.Mockito; -//import org.springframework.beans.factory.annotation.Autowired; -//import org.springframework.beans.factory.annotation.Value; -//import org.springframework.boot.test.context.SpringBootTest; -//import org.springframework.context.annotation.Profile; -//import org.springframework.test.context.ActiveProfiles; -//import org.springframework.test.context.TestPropertySource; -//import org.springframework.web.bind.MethodArgumentNotValidException; -//import org.springframework.web.reactive.function.client.WebClient; -// -//@SpringBootTest(classes = SmsCertificationController.class) -//public class SmsCertificationControllerTest { -// -// @Autowired -// WebClient webClient; -// -// @Autowired -// RedisService redisService; -// @Autowired -// SmsCertificationService smsCertificationService; -// -// @Value("${SPRING_PROFILE}") -// String value; -// -// @Test -// @DisplayName("인자 유효성 검사 동작 확인") -// public void testRequestSmsVerificationCodeValidation() { -// System.out.println("mockWebClient = " + webClient); -// System.out.println("mockRedisService = " + redisService); -// System.out.println("smsCertificationService = " + smsCertificationService); -// System.out.println("value = " + value); -// -// -// //Mock Object DI -// -// SmsCertificationController smsCertificationController -// = new SmsCertificationController(smsCertificationService); -// -// SmsVerificationCodeRequestDTO verificationCodeTestDto1 -// = new SmsVerificationCodeRequestDTO("010-1234-1234"); -// -// Assertions.assertThrows(MethodArgumentNotValidException.class, () -> { -// smsCertificationController.sendMessageWithVerificationCode(verificationCodeTestDto1); -// }); -// } -//} +package com.tikitaka.naechinso.unit.controller; + +import com.tikitaka.naechinso.domain.sms.SmsCertificationController; +import com.tikitaka.naechinso.domain.sms.dto.SmsVerificationCodeRequestDTO; +import com.tikitaka.naechinso.global.config.redis.RedisService; +import com.tikitaka.naechinso.domain.sms.SmsCertificationService; +import com.tikitaka.naechinso.domain.sms.SmsCertificationServiceImpl; +import org.hibernate.service.spi.InjectService; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; +import org.mockito.InjectMocks; +import org.mockito.Mock; +import org.mockito.Mockito; +import org.mockito.junit.jupiter.MockitoExtension; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.context.annotation.Profile; +import org.springframework.test.context.ActiveProfiles; +import org.springframework.test.context.TestPropertySource; +import org.springframework.test.web.servlet.MockMvc; +import org.springframework.test.web.servlet.MockMvcBuilder; +import org.springframework.test.web.servlet.setup.MockMvcBuilders; +import org.springframework.web.bind.MethodArgumentNotValidException; +import org.springframework.web.reactive.function.client.WebClient; + +@ExtendWith(MockitoExtension.class) +public class SmsCertificationControllerTest { + + @InjectMocks + private SmsCertificationController smsCertificationController; + @Mock + private SmsCertificationService smsCertificationService; + //HTTP Method 호출용 MockMvc + private MockMvc mockMvc; + @BeforeEach + public void init() { + mockMvc = MockMvcBuilders.standaloneSetup(smsCertificationController).build(); + + } + + @Value("${spring.profiles.active}") + String value; + + @Test + @DisplayName("인자 유효성 검사 동작 확인") + public void testRequestSmsVerificationCodeValidation() { + + } +} diff --git a/src/test/java/com/tikitaka/naechinso/unit/service/SmsCertificationServiceTest.java b/src/test/java/com/tikitaka/naechinso/unit/service/SmsCertificationServiceTest.java new file mode 100644 index 0000000..d1ab069 --- /dev/null +++ b/src/test/java/com/tikitaka/naechinso/unit/service/SmsCertificationServiceTest.java @@ -0,0 +1,189 @@ +package com.tikitaka.naechinso.unit.service; + +import com.tikitaka.naechinso.domain.member.MemberRepository; +import com.tikitaka.naechinso.domain.member.entity.Member; +import com.tikitaka.naechinso.domain.recommend.RecommendService; +import com.tikitaka.naechinso.domain.sms.SmsCertificationService; +import com.tikitaka.naechinso.domain.sms.SmsCertificationServiceImpl; +import com.tikitaka.naechinso.domain.sms.dto.SmsCertificationRequestDTO; +import com.tikitaka.naechinso.domain.sms.dto.SmsCertificationSuccessResponseDTO; +import com.tikitaka.naechinso.global.common.response.TokenResponseDTO; +import com.tikitaka.naechinso.global.config.redis.RedisService; +import com.tikitaka.naechinso.global.config.security.dto.JwtDTO; +import com.tikitaka.naechinso.global.config.security.jwt.JwtTokenProvider; +import com.tikitaka.naechinso.infra.sms.SmsService; +import org.junit.Before; +import org.junit.Rule; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; +import org.mockito.InjectMocks; +import org.mockito.Mock; +import org.mockito.Mockito; +import org.mockito.Spy; +import org.mockito.junit.jupiter.MockitoExtension; +import org.springframework.test.util.ReflectionTestUtils; + +import java.time.Duration; +import java.util.Optional; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.mockito.BDDMockito.*; + + +@ExtendWith(MockitoExtension.class) +public class SmsCertificationServiceTest { + + @InjectMocks + private SmsCertificationServiceImpl smsCertificationService; + @Mock + private MemberRepository memberRepository; + @Mock + private RecommendService recommendService; + @Mock + private RedisService redisService; + @Mock + private JwtTokenProvider jwtTokenProvider; + + //Redis Config + private final String VERIFICATION_PREFIX = "sms:"; + private final int VERIFICATION_TIME_LIMIT = 3 * 60; + + @DisplayName("가짜 메세지 전송 성공과 레디스 저장 테스트") + @Test + void testSendFakeSms() { + //given + final String receiver = "01012345678"; + final Duration verificationTimeLimit = Duration.ofSeconds(VERIFICATION_TIME_LIMIT); + + //when + String verificationCode = smsCertificationService.sendVerificationMessage(receiver) + .substring(12, 18); + + //then + verify(redisService, times(1)) + .setValues(VERIFICATION_PREFIX + receiver, verificationCode, verificationTimeLimit); + assertThat(verificationCode.length()).isEqualTo(6); + } + + + @DisplayName("가입하지 않은 회원의 RegisterToken 발급 테스트") + @Test + void testVerifyCodeByNotSignedUpMember() { + //given + final String receiver = "01012345678"; + final Duration verificationTimeLimit = Duration.ofSeconds(VERIFICATION_TIME_LIMIT); + final String verificationCode = smsCertificationService.sendVerificationMessage(receiver) + .substring(12, 18); + final SmsCertificationRequestDTO requestDTO + = SmsCertificationRequestDTO.builder() + .phoneNumber(receiver) + .code(verificationCode) + .build(); + final String key = VERIFICATION_PREFIX + receiver; + + given(redisService.hasKey(key)).willReturn(true); + given(redisService.getValues(key)).willReturn(verificationCode); + given(memberRepository.findByPhone(receiver)).willReturn(Optional.empty()); + given(recommendService.existsByReceiverPhoneAndSenderNotNull(receiver)).willReturn(false); + given(jwtTokenProvider.generateRegisterToken(new JwtDTO(receiver))).willReturn("rgT"); + + //when + SmsCertificationSuccessResponseDTO responseDTO + = smsCertificationService.verifyCode(requestDTO); + + //then + verify(redisService, times(1)) + .setValues(VERIFICATION_PREFIX + receiver, verificationCode, verificationTimeLimit); + verify(redisService, times(1)).hasKey(key); + verify(redisService, times(1)).getValues(key); + verify(memberRepository, times(1)).findByPhone(receiver); + verify(recommendService, times(1)).existsByReceiverPhoneAndSenderNotNull(receiver); + verify(jwtTokenProvider, times(1)).generateRegisterToken(new JwtDTO(receiver)); + assertThat(responseDTO.getAccessToken()).isNull(); + assertThat(responseDTO.getRefreshToken()).isNull(); + assertThat(responseDTO.getRegisterToken()).isEqualTo("rgT"); + assertThat(responseDTO.getRecommendReceived()).isFalse(); + } + + @DisplayName("가입한 회원의 Token 발급 테스트") + @Test + void testVerifyCodeBySignedUpMember() { + //given + final String receiver = "01012345678"; + final Duration verificationTimeLimit = Duration.ofSeconds(VERIFICATION_TIME_LIMIT); + final String verificationCode = smsCertificationService.sendVerificationMessage(receiver) + .substring(12, 18); + final SmsCertificationRequestDTO requestDTO = SmsCertificationRequestDTO.builder() + .phoneNumber(receiver) + .code(verificationCode) + .build(); + final String key = VERIFICATION_PREFIX + receiver; + final Member member = Member.builder().build(); + + given(redisService.hasKey(key)).willReturn(true); + given(redisService.getValues(key)).willReturn(verificationCode); + given(memberRepository.findByPhone(receiver)).willReturn(Optional.of(member)); + given(recommendService.existsByReceiverPhoneAndSenderNotNull(receiver)).willReturn(false); + given(jwtTokenProvider.generateToken(new JwtDTO(receiver, "ROLE_USER"))) + .willReturn(TokenResponseDTO.builder().accessToken("aT").refreshToken("rfT").build()); + + //when + SmsCertificationSuccessResponseDTO responseDTO + = smsCertificationService.verifyCode(requestDTO); + + //then + verify(redisService, times(1)) + .setValues(VERIFICATION_PREFIX + receiver, verificationCode, verificationTimeLimit); + verify(redisService, times(1)).hasKey(key); + verify(redisService, times(1)).getValues(key); + verify(memberRepository, times(1)).findByPhone(receiver); + verify(recommendService, times(1)).existsByReceiverPhoneAndSenderNotNull(receiver); + verify(jwtTokenProvider, times(1)).generateToken(new JwtDTO(receiver, "ROLE_USER")); + + assertThat(responseDTO.getAccessToken()).isEqualTo("aT"); + assertThat(responseDTO.getRefreshToken()).isEqualTo("rfT"); + assertThat(responseDTO.getRegisterToken()).isNull(); + assertThat(responseDTO.getRecommendReceived()).isFalse(); + } + +// +// @DisplayName("인증번호 시간 만료 테스트") +// @Test +// void testVerifyCodeBySignedUpMember() { +// //given +// final String receiver = "01012345678"; +// final Duration verificationTimeLimit = Duration.ofSeconds(VERIFICATION_TIME_LIMIT); +// final String verificationCode = smsCertificationService.sendVerificationMessage(receiver) +// .substring(12, 18); +// final SmsCertificationRequestDTO requestDTO = SmsCertificationRequestDTO.builder() +// .phoneNumber(receiver) +// .code(verificationCode) +// .build(); +// final String key = VERIFICATION_PREFIX + receiver; +// +// given(redisService.hasKey(key)).willReturn(true); +// given(redisService.getValues(key)).willReturn(verificationCode); +// given(memberRepository.findByPhone(receiver)).willReturn(Optional.empty()); +// given(recommendService.existsByReceiverPhoneAndSenderNotNull(receiver)).willReturn(false); +// given(jwtTokenProvider.generateRegisterToken(new JwtDTO(receiver))).willReturn("rT"); +// +// //when +// SmsCertificationSuccessResponseDTO responseDTO +// = smsCertificationService.verifyCode(requestDTO); +// +// //then +// verify(redisService, times(1)) +// .setValues(VERIFICATION_PREFIX + receiver, verificationCode, verificationTimeLimit); +// verify(redisService, times(1)).hasKey(key); +// verify(redisService, times(1)).getValues(key); +// verify(memberRepository, times(1)).findByPhone(receiver); +// verify(recommendService, times(1)).existsByReceiverPhoneAndSenderNotNull(receiver); +// verify(jwtTokenProvider, times(1)).generateRegisterToken(new JwtDTO(receiver)); +// assertThat(responseDTO.getAccessToken()).isNull(); +// assertThat(responseDTO.getRefreshToken()).isNull(); +// assertThat(responseDTO.getRegisterToken()).isEqualTo("rT"); +// assertThat(responseDTO.getRecommendReceived()).isFalse(); +// } + +} diff --git a/src/test/resources/application.yml b/src/test/resources/application.yml index 7808ac2..3890df8 100644 --- a/src/test/resources/application.yml +++ b/src/test/resources/application.yml @@ -1,35 +1,27 @@ server: - port: ${PORT:8080} + port: 8080 spring: profiles: - active: ${SPRING_PROFILE} - # .env import - config: - import: optional:file:.env[.properties] - activate: - on-profile: local - # Using POSTGRESQL + active: local datasource: - url: jdbc:postgresql://${POSTGRES_HOST}:${POSTGRES_PORT}/${POSTGRES_DB} - username: ${POSTGRES_USER} - password: ${POSTGRES_PASSWORD} driver-class-name: org.postgresql.Driver + url: jdbc:postgresql://localhost:5432/tikitaka + username: tikitaka + password: tikitaka1234 + redis: + host: localhost + port: 6379 jpa: database: postgresql database-platform: org.hibernate.dialect.PostgreSQLDialect - # local - create - # update - dev - # none - local hibernate: - ddl-auto: none + ddl-auto: create-drop properties: hibernate: dialect: org.hibernate.dialect.PostgreSQLDialect database-platform: org.hibernate.dialect.PostgreSQLDialect - # show_sql: true - # format_sql: true springfox: documentation: @@ -39,3 +31,6 @@ spring: logging.level: org.hibernate.SQL: debug org.hibernate.type: trace + +jwt: + secret-key: example1234 \ No newline at end of file From fd4debe92275a1380c9fba67ec92c1fdd6643a22 Mon Sep 17 00:00:00 2001 From: gengminy Date: Wed, 5 Oct 2022 21:24:42 +0900 Subject: [PATCH 13/72] =?UTF-8?q?:hammer:=20fix(user):=20=EC=9E=84?= =?UTF-8?q?=EC=8B=9C=ED=9A=8C=EC=9B=90=EC=9D=98=20=EC=B6=94=EC=B2=9C?= =?UTF-8?q?=EC=82=AC=20=EC=9E=91=EC=84=B1=20=EC=88=98=EC=A0=95=20#28?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../domain/member/MemberController.java | 86 +++++++++++--- .../domain/member/MemberService.java | 38 +++--- ...o.java => MemberCommonJoinRequestDTO.java} | 4 +- ...eDto.java => MemberCommonResponseDTO.java} | 6 +- ...o.java => MemberDetailJoinRequestDTO.java} | 5 +- ...eDto.java => MemberDetailResponseDTO.java} | 15 +-- .../member/dto/MemberJobUpdateRequestDTO.java | 29 +++++ .../domain/member/entity/Member.java | 7 ++ .../domain/member/entity/MemberDetail.java | 8 +- .../domain/recommend/RecommendController.java | 13 +-- .../domain/recommend/RecommendService.java | 108 ++++++++++++------ ...=> RecommendAcceptWithJoinRequestDTO.java} | 5 +- .../dto/RecommendJoinRequestDTO.java | 4 + .../dto/RecommendMemberAcceptRequestDTO.java | 4 + ...ndMemberAcceptWithUpdateJobRequestDTO.java | 45 ++++++++ .../recommend/dto/RecommendResponseDTO.java | 3 + .../domain/recommend/entity/Recommend.java | 39 ++++++- 17 files changed, 319 insertions(+), 100 deletions(-) rename src/main/java/com/tikitaka/naechinso/domain/member/dto/{MemberCommonJoinRequestDto.java => MemberCommonJoinRequestDTO.java} (98%) rename src/main/java/com/tikitaka/naechinso/domain/member/dto/{MemberCommonResponseDto.java => MemberCommonResponseDTO.java} (83%) rename src/main/java/com/tikitaka/naechinso/domain/member/dto/{MemberDetailJoinRequestDto.java => MemberDetailJoinRequestDTO.java} (90%) rename src/main/java/com/tikitaka/naechinso/domain/member/dto/{MemberDetailResponseDto.java => MemberDetailResponseDTO.java} (85%) create mode 100644 src/main/java/com/tikitaka/naechinso/domain/member/dto/MemberJobUpdateRequestDTO.java rename src/main/java/com/tikitaka/naechinso/domain/recommend/dto/{RecommendAcceptRequestDTO.java => RecommendAcceptWithJoinRequestDTO.java} (95%) create mode 100644 src/main/java/com/tikitaka/naechinso/domain/recommend/dto/RecommendMemberAcceptWithUpdateJobRequestDTO.java diff --git a/src/main/java/com/tikitaka/naechinso/domain/member/MemberController.java b/src/main/java/com/tikitaka/naechinso/domain/member/MemberController.java index 888d235..d34b836 100644 --- a/src/main/java/com/tikitaka/naechinso/domain/member/MemberController.java +++ b/src/main/java/com/tikitaka/naechinso/domain/member/MemberController.java @@ -4,6 +4,7 @@ import com.tikitaka.naechinso.domain.member.entity.Member; import com.tikitaka.naechinso.domain.recommend.RecommendService; import com.tikitaka.naechinso.domain.recommend.dto.RecommendMemberAcceptRequestDTO; +import com.tikitaka.naechinso.domain.recommend.dto.RecommendMemberAcceptWithUpdateJobRequestDTO; import com.tikitaka.naechinso.domain.recommend.dto.RecommendResponseDTO; import com.tikitaka.naechinso.global.annotation.AuthMember; import com.tikitaka.naechinso.global.config.CommonApiResponse; @@ -31,68 +32,99 @@ public class MemberController { private final JwtTokenProvider jwtTokenService; @GetMapping - @ApiOperation(value = "유저 자신의 모든 정보를 가져온다 (AccessToken 필요)") - public CommonApiResponse getMyInformation( + @ApiOperation(value = "유저 자신의 모든 정보를 가져온다 (AccessToken)") + public CommonApiResponse getMyInformation( HttpServletRequest request, @ApiIgnore @AuthMember Member member) { //로그인 상태가 아닌 경우 401 if (member == null) { throw new UnauthorizedException(ErrorCode.UNAUTHORIZED_USER); } - return CommonApiResponse.of(MemberCommonResponseDto.of(member)); + return CommonApiResponse.of(MemberCommonResponseDTO.of(member)); } // @PostMapping("/join") // @ApiOperation(value = "공통 유저를 기본 정보로 회원가입 시킨다 (registerToken 필요)") -// public CommonApiResponse joinCommonMember( +// public CommonApiResponse joinCommonMember( // HttpServletRequest request, -// @Valid @RequestBody MemberCommonJoinRequestDto dto) +// @Valid @RequestBody MemberCommonJoinRequestDTO dto) // { // String registerToken = request.getHeader("Authorization"); // if (StringUtils.isBlank(registerToken) || !jwtTokenService.validateToken(registerToken)) { // throw new UnauthorizedException(ErrorCode.NO_TOKEN); // } // -// final MemberCommonResponseDto res = memberService.createCommonMember(dto); +// final MemberCommonResponseDTO res = memberService.createCommonMember(dto); // return CommonApiResponse.of(res); // } @GetMapping("/detail") @ApiOperation(value = "회원가입 세부 정보를 가져온다 (AccessToken 필요)") - public CommonApiResponse getMemberDetail( + public CommonApiResponse getMemberDetail( @ApiIgnore @AuthMember Member member) { //로그인 상태가 아닌 경우 401 if (member == null) { throw new UnauthorizedException(ErrorCode.UNAUTHORIZED_USER); } - final MemberDetailResponseDto res = memberService.readDetail(member); + final MemberDetailResponseDTO res = memberService.readDetail(member); return CommonApiResponse.of(res); } + @PatchMapping("/job") + @ApiOperation(value = "직업 정보를 업데이트 한다 (AccessToken)") + public CommonApiResponse setMemberJob( + @RequestBody MemberJobUpdateRequestDTO dto, + @ApiIgnore @AuthMember Member member) + { + //로그인 상태가 아닌 경우 401 + if (member == null) { + throw new UnauthorizedException(ErrorCode.UNAUTHORIZED_USER); + } + return CommonApiResponse.of(memberService.updateJob(member, dto)); + } + + @PostMapping("/join") + @ApiOperation(value = "유저를 공통 정보로 가입시킨다 (RegisterToken)") + public CommonApiResponse join( + HttpServletRequest request, + @Valid @RequestBody MemberDetailJoinRequestDTO dto + ) + { + return null; +// //로그인 상태가 아닌 경우 401 +// if (member == null) { +// throw new UnauthorizedException(ErrorCode.UNAUTHORIZED_USER); +// } +// final MemberDetailResponseDTO res = memberService.createDetail(member, dto); +// return CommonApiResponse.of(res); + } + + + @PostMapping("/join/detail") @ApiOperation(value = "회원가입 세부 정보를 입력하여 최종 가입시킨다 (AccessToken)") - public CommonApiResponse setMemberDetail( - @Valid @RequestBody MemberDetailJoinRequestDto dto, + public CommonApiResponse setMemberDetail( + @Valid @RequestBody MemberDetailJoinRequestDTO dto, @ApiIgnore @AuthMember Member member) { //로그인 상태가 아닌 경우 401 if (member == null) { throw new UnauthorizedException(ErrorCode.UNAUTHORIZED_USER); } - final MemberDetailResponseDto res = memberService.createDetail(member, dto); + final MemberDetailResponseDTO res = memberService.createDetail(member, dto); return CommonApiResponse.of(res); } //페이징 처리 추가할 예정 @GetMapping("/find") @ApiOperation(value = "[Admin]현재 가입한 모든 유저를 불러온다 (AccessToken)") - public CommonApiResponse> getMyInformation() { + public CommonApiResponse> getMyInformation() { return CommonApiResponse.of(memberService.findAll()); } @PostMapping("/recommend") @ApiOperation(value = "다른 유저의 추천사를 작성한다 (AccessToken)") - public CommonApiResponse createRecommend( + public CommonApiResponse createRecommend( @RequestBody RecommendMemberAcceptRequestDTO dto, @ApiIgnore @AuthMember Member member) { @@ -104,11 +136,37 @@ public CommonApiResponse createRecommend( } + /** + * @// TODO: 2022/10/05 직업 정보가 없는 사람이 가입할 때 직업 정보 입력해야 하는 처리 필요 + * */ @PatchMapping("/recommend/{uuid}/accept") @ApiOperation(value = "요청받은 uuid 추천사에 자신을 추천인으로 등록한다 (AccessToken)") public CommonApiResponse updateRecommendByUuid( @PathVariable("uuid") String uuid, - @Valid @RequestBody RecommendMemberAcceptRequestDTO dto, + @Valid @RequestBody RecommendMemberAcceptWithUpdateJobRequestDTO dto, + @ApiIgnore @AuthMember Member member) + { + //로그인 상태가 아닌 경우 401 + if (member == null) { + throw new UnauthorizedException(ErrorCode.UNAUTHORIZED_USER); + } + if (member.getDetail() == null) { + throw new UnauthorizedException(ErrorCode.FORBIDDEN_USER); + } + String phone = member.getPhone(); + RecommendResponseDTO recommendResponseDTO = recommendService.updateRecommendMemberAccept(uuid, phone, dto); + return CommonApiResponse.of(recommendResponseDTO); + } + + + /** + * 직업 정보가 없을 경우 내 직업 정보를 업데이트하고 추천인을 가입시킨다 + * */ + @PatchMapping("/recommend/{uuid}/accept/job") + @ApiOperation(value = "요청받은 uuid 추천사에 자신을 추천인으로 등록하며 직업 정보를 업데이트 한다 (AccessToken)") + public CommonApiResponse updateRecommendByUuidWithJob( + @PathVariable("uuid") String uuid, + @Valid @RequestBody RecommendMemberAcceptWithUpdateJobRequestDTO dto, @ApiIgnore @AuthMember Member member) { //로그인 상태가 아닌 경우 401 diff --git a/src/main/java/com/tikitaka/naechinso/domain/member/MemberService.java b/src/main/java/com/tikitaka/naechinso/domain/member/MemberService.java index 46bdae6..dcd8c60 100644 --- a/src/main/java/com/tikitaka/naechinso/domain/member/MemberService.java +++ b/src/main/java/com/tikitaka/naechinso/domain/member/MemberService.java @@ -1,9 +1,6 @@ package com.tikitaka.naechinso.domain.member; -import com.tikitaka.naechinso.domain.member.dto.MemberCommonJoinRequestDto; -import com.tikitaka.naechinso.domain.member.dto.MemberCommonResponseDto; -import com.tikitaka.naechinso.domain.member.dto.MemberDetailJoinRequestDto; -import com.tikitaka.naechinso.domain.member.dto.MemberDetailResponseDto; +import com.tikitaka.naechinso.domain.member.dto.*; import com.tikitaka.naechinso.domain.member.entity.Member; import com.tikitaka.naechinso.domain.member.entity.MemberDetail; import com.tikitaka.naechinso.global.common.response.TokenResponseDTO; @@ -15,13 +12,11 @@ import com.tikitaka.naechinso.global.error.exception.NotFoundException; import lombok.RequiredArgsConstructor; import org.springframework.security.authentication.UsernamePasswordAuthenticationToken; -import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder; import org.springframework.security.core.authority.SimpleGrantedAuthority; import org.springframework.security.core.context.SecurityContextHolder; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; -import java.util.Arrays; import java.util.List; import java.util.Optional; import java.util.stream.Collectors; @@ -35,14 +30,14 @@ public class MemberService { private final MemberDetailRepository memberDetailRepository; private final JwtTokenProvider jwtTokenProvider; - public List findAll() { - List memberList = memberRepository.findAll().stream() - .map(member -> MemberCommonResponseDto.of(member)).collect(Collectors.toList()); + public List findAll() { + List memberList = memberRepository.findAll().stream() + .map(member -> MemberCommonResponseDTO.of(member)).collect(Collectors.toList()); return memberList; } - public MemberCommonResponseDto createCommonMember(MemberCommonJoinRequestDto dto) { + public MemberCommonResponseDTO createCommonMember(MemberCommonJoinRequestDTO dto) { //이미 존재하는 유저일 경우 400 Optional checkMember = memberRepository.findByPhone(dto.getPhone()); @@ -50,10 +45,10 @@ public MemberCommonResponseDto createCommonMember(MemberCommonJoinRequestDto dto throw new BadRequestException(ErrorCode.USER_ALREADY_EXIST); } - Member member = MemberCommonJoinRequestDto.toCommonMember(dto); + Member member = MemberCommonJoinRequestDTO.toCommonMember(dto); memberRepository.save(member); - MemberCommonResponseDto res = MemberCommonResponseDto.of(member); + MemberCommonResponseDTO res = MemberCommonResponseDTO.of(member); return res; } @@ -75,17 +70,17 @@ public TokenResponseDTO login(String phone) { } - public MemberDetailResponseDto readDetail(Member member) { + public MemberDetailResponseDTO readDetail(Member member) { // // Member checkMember = memberRepository.findByPhone(phone) // .orElseThrow(() -> new BadRequestException(ErrorCode.USER_NOT_FOUND)); - MemberDetailResponseDto dto = MemberDetailResponseDto.of(member); + MemberDetailResponseDTO dto = MemberDetailResponseDTO.of(member); return dto; } - public MemberDetailResponseDto createDetail(Member authMember, MemberDetailJoinRequestDto dto) { + public MemberDetailResponseDTO createDetail(Member authMember, MemberDetailJoinRequestDTO dto) { //영속성 유지를 위한 fetch Member member = memberRepository.findById(authMember.getId()) .orElseThrow(() -> new NotFoundException(ErrorCode.USER_NOT_FOUND)); @@ -97,6 +92,17 @@ public MemberDetailResponseDto createDetail(Member authMember, MemberDetailJoinR MemberDetail detail = MemberDetail.of(member, dto); memberDetailRepository.save(detail); - return MemberDetailResponseDto.of(detail); + return MemberDetailResponseDTO.of(detail); } + + public MemberCommonResponseDTO updateJob(Member authMember, MemberJobUpdateRequestDTO dto){ + //영속성 유지를 위한 fetch + Member member = memberRepository.findById(authMember.getId()) + .orElseThrow(() -> new NotFoundException(ErrorCode.USER_NOT_FOUND)); + + member.setJob(dto); + memberRepository.save(member); + return MemberCommonResponseDTO.of(member); + } + } diff --git a/src/main/java/com/tikitaka/naechinso/domain/member/dto/MemberCommonJoinRequestDto.java b/src/main/java/com/tikitaka/naechinso/domain/member/dto/MemberCommonJoinRequestDTO.java similarity index 98% rename from src/main/java/com/tikitaka/naechinso/domain/member/dto/MemberCommonJoinRequestDto.java rename to src/main/java/com/tikitaka/naechinso/domain/member/dto/MemberCommonJoinRequestDTO.java index ad4ea66..298bab5 100644 --- a/src/main/java/com/tikitaka/naechinso/domain/member/dto/MemberCommonJoinRequestDto.java +++ b/src/main/java/com/tikitaka/naechinso/domain/member/dto/MemberCommonJoinRequestDTO.java @@ -17,7 +17,7 @@ @Getter @Builder @ToString -public class MemberCommonJoinRequestDto { +public class MemberCommonJoinRequestDTO { @ApiModelProperty(example = "01010001000") @NotBlank(message = "전화번호를 입력해주세요") @Pattern(regexp = "[0-9]{10,11}", message = "하이픈 없는 10~11자리 숫자를 입력해주세요") @@ -66,7 +66,7 @@ public class MemberCommonJoinRequestDto { @NotBlank(message = "직장 위치를 입력해주세요") private String jobLocation; - public static Member toCommonMember(MemberCommonJoinRequestDto dto) { + public static Member toCommonMember(MemberCommonJoinRequestDTO dto) { Member member = Member.builder() .phone(dto.phone) .name(dto.name) diff --git a/src/main/java/com/tikitaka/naechinso/domain/member/dto/MemberCommonResponseDto.java b/src/main/java/com/tikitaka/naechinso/domain/member/dto/MemberCommonResponseDTO.java similarity index 83% rename from src/main/java/com/tikitaka/naechinso/domain/member/dto/MemberCommonResponseDto.java rename to src/main/java/com/tikitaka/naechinso/domain/member/dto/MemberCommonResponseDTO.java index e5b74f2..6940ad6 100644 --- a/src/main/java/com/tikitaka/naechinso/domain/member/dto/MemberCommonResponseDto.java +++ b/src/main/java/com/tikitaka/naechinso/domain/member/dto/MemberCommonResponseDTO.java @@ -14,7 +14,7 @@ @Getter @Builder @ToString -public class MemberCommonResponseDto { +public class MemberCommonResponseDTO { private String phone; @@ -26,8 +26,8 @@ public class MemberCommonResponseDto { private int age; - public static MemberCommonResponseDto of(Member member) { - MemberCommonResponseDto res = MemberCommonResponseDto.builder() + public static MemberCommonResponseDTO of(Member member) { + MemberCommonResponseDTO res = MemberCommonResponseDTO.builder() .phone(member.getPhone()) .role(member.getRole()) .name(member.getName()) diff --git a/src/main/java/com/tikitaka/naechinso/domain/member/dto/MemberDetailJoinRequestDto.java b/src/main/java/com/tikitaka/naechinso/domain/member/dto/MemberDetailJoinRequestDTO.java similarity index 90% rename from src/main/java/com/tikitaka/naechinso/domain/member/dto/MemberDetailJoinRequestDto.java rename to src/main/java/com/tikitaka/naechinso/domain/member/dto/MemberDetailJoinRequestDTO.java index 8d162c0..5708afb 100644 --- a/src/main/java/com/tikitaka/naechinso/domain/member/dto/MemberDetailJoinRequestDto.java +++ b/src/main/java/com/tikitaka/naechinso/domain/member/dto/MemberDetailJoinRequestDTO.java @@ -1,12 +1,9 @@ package com.tikitaka.naechinso.domain.member.dto; -import com.tikitaka.naechinso.domain.member.constant.Gender; -import com.tikitaka.naechinso.domain.member.entity.Member; import io.swagger.annotations.ApiModelProperty; import lombok.*; import org.hibernate.validator.constraints.Length; -import javax.persistence.Column; import javax.validation.constraints.*; /** @@ -18,7 +15,7 @@ @Getter @Builder @ToString -public class MemberDetailJoinRequestDto { +public class MemberDetailJoinRequestDTO { //추천인 정보 // @ApiModelProperty(example = "180") diff --git a/src/main/java/com/tikitaka/naechinso/domain/member/dto/MemberDetailResponseDto.java b/src/main/java/com/tikitaka/naechinso/domain/member/dto/MemberDetailResponseDTO.java similarity index 85% rename from src/main/java/com/tikitaka/naechinso/domain/member/dto/MemberDetailResponseDto.java rename to src/main/java/com/tikitaka/naechinso/domain/member/dto/MemberDetailResponseDTO.java index ed2815f..9391403 100644 --- a/src/main/java/com/tikitaka/naechinso/domain/member/dto/MemberDetailResponseDto.java +++ b/src/main/java/com/tikitaka/naechinso/domain/member/dto/MemberDetailResponseDTO.java @@ -8,10 +8,6 @@ import com.tikitaka.naechinso.global.error.exception.NotFoundException; import lombok.*; -import javax.persistence.Column; -import javax.persistence.EnumType; -import javax.persistence.Enumerated; - /** * 추천인 및 추천 받는 사람 공통 가입을 위한 Dto입니다 * @author gengminy 220924 @@ -21,9 +17,8 @@ @Getter @Builder @ToString -public class MemberDetailResponseDto { +public class MemberDetailResponseDTO { -// private Member member; //추천인 정보 private String phone; @@ -67,7 +62,7 @@ public class MemberDetailResponseDto { private String eduLevel; - public static MemberDetailResponseDto of(Member member) { + public static MemberDetailResponseDTO of(Member member) { MemberDetail detail = member.getDetail(); //회원가입 정보가 없으면 null if (detail == null) { @@ -76,12 +71,12 @@ public static MemberDetailResponseDto of(Member member) { return buildDetail(detail); } - public static MemberDetailResponseDto of(MemberDetail memberDetail) { + public static MemberDetailResponseDTO of(MemberDetail memberDetail) { return buildDetail(memberDetail); } - private static MemberDetailResponseDto buildDetail(MemberDetail detail) { - MemberDetailResponseDtoBuilder dtoBuilder = MemberDetailResponseDto.builder(); + private static MemberDetailResponseDTO buildDetail(MemberDetail detail) { + MemberDetailResponseDTOBuilder dtoBuilder = MemberDetailResponseDTO.builder(); Member member = detail.getMember(); //멤버 정보가 연결되어 있으면 가져옴 diff --git a/src/main/java/com/tikitaka/naechinso/domain/member/dto/MemberJobUpdateRequestDTO.java b/src/main/java/com/tikitaka/naechinso/domain/member/dto/MemberJobUpdateRequestDTO.java new file mode 100644 index 0000000..9bd4ba0 --- /dev/null +++ b/src/main/java/com/tikitaka/naechinso/domain/member/dto/MemberJobUpdateRequestDTO.java @@ -0,0 +1,29 @@ +package com.tikitaka.naechinso.domain.member.dto; + +import io.swagger.annotations.ApiModelProperty; +import lombok.*; + +import javax.validation.constraints.NotBlank; + +/** + * 직업 정보 업데이트를 위한 DTO + * @author gengminy 221005 + * */ +@AllArgsConstructor +@NoArgsConstructor +@Getter +@Builder +@ToString +public class MemberJobUpdateRequestDTO { + @ApiModelProperty(example = "카카오") + @NotBlank(message = "직장명을 입력해주세요") + private String jobName; + + @ApiModelProperty(example = "개발자") + @NotBlank(message = "직장 부서를 입력해주세요") + private String jobPart; + + @ApiModelProperty(example = "판교") + @NotBlank(message = "직장 위치를 입력해주세요") + private String jobLocation; +} diff --git a/src/main/java/com/tikitaka/naechinso/domain/member/entity/Member.java b/src/main/java/com/tikitaka/naechinso/domain/member/entity/Member.java index 4d2fe06..057259b 100644 --- a/src/main/java/com/tikitaka/naechinso/domain/member/entity/Member.java +++ b/src/main/java/com/tikitaka/naechinso/domain/member/entity/Member.java @@ -3,6 +3,7 @@ import com.fasterxml.jackson.annotation.JsonIgnore; import com.tikitaka.naechinso.domain.member.constant.Gender; import com.tikitaka.naechinso.domain.member.constant.Role; +import com.tikitaka.naechinso.domain.member.dto.MemberJobUpdateRequestDTO; import com.tikitaka.naechinso.domain.recommend.entity.Recommend; import com.tikitaka.naechinso.global.config.entity.BaseEntity; import lombok.*; @@ -97,4 +98,10 @@ public class Member extends BaseEntity { public void setDetail(MemberDetail memberDetail) { this.detail = memberDetail; } + + public void setJob(MemberJobUpdateRequestDTO requestDTO) { + this.jobName = requestDTO.getJobName(); + this.jobLocation = requestDTO.getJobLocation(); + this.jobPart = requestDTO.getJobPart(); + } } diff --git a/src/main/java/com/tikitaka/naechinso/domain/member/entity/MemberDetail.java b/src/main/java/com/tikitaka/naechinso/domain/member/entity/MemberDetail.java index bdfe570..1369af4 100644 --- a/src/main/java/com/tikitaka/naechinso/domain/member/entity/MemberDetail.java +++ b/src/main/java/com/tikitaka/naechinso/domain/member/entity/MemberDetail.java @@ -1,11 +1,9 @@ package com.tikitaka.naechinso.domain.member.entity; import com.fasterxml.jackson.annotation.JsonIgnore; -import com.tikitaka.naechinso.domain.member.dto.MemberDetailJoinRequestDto; +import com.tikitaka.naechinso.domain.member.dto.MemberDetailJoinRequestDTO; import com.tikitaka.naechinso.domain.point.entity.Point; import com.tikitaka.naechinso.global.config.entity.BaseEntity; -import com.tikitaka.naechinso.global.config.entity.BaseTimeEntity; -import io.swagger.annotations.ApiModelProperty; import lombok.*; import javax.persistence.*; @@ -99,7 +97,7 @@ public class MemberDetail extends BaseEntity { private Member member; - public static MemberDetail of(MemberDetailJoinRequestDto dto) { + public static MemberDetail of(MemberDetailJoinRequestDTO dto) { return MemberDetail.builder() .height(dto.getHeight()) .address(dto.getAddress()) @@ -118,7 +116,7 @@ public static MemberDetail of(MemberDetailJoinRequestDto dto) { .build(); } - public static MemberDetail of(Member member, MemberDetailJoinRequestDto dto) { + public static MemberDetail of(Member member, MemberDetailJoinRequestDTO dto) { return MemberDetail.builder() .height(dto.getHeight()) .address(dto.getAddress()) diff --git a/src/main/java/com/tikitaka/naechinso/domain/recommend/RecommendController.java b/src/main/java/com/tikitaka/naechinso/domain/recommend/RecommendController.java index 067fd89..4fd793e 100644 --- a/src/main/java/com/tikitaka/naechinso/domain/recommend/RecommendController.java +++ b/src/main/java/com/tikitaka/naechinso/domain/recommend/RecommendController.java @@ -10,7 +10,6 @@ import io.swagger.annotations.ApiOperation; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; -import org.apache.commons.lang3.StringUtils; import org.springframework.web.bind.annotation.*; import springfox.documentation.annotations.ApiIgnore; @@ -39,7 +38,7 @@ public CommonApiResponse getRecommends( } @PostMapping - @ApiOperation(value = "추천서를 작성한 후, 추천인을 회원가입 시킨다. (registerToken 필요)") + @ApiOperation(value = "추천서를 작성한 후, 추천인을 회원가입 시킨다. RegisterToken)") public CommonApiResponse createRecommendNewSender( HttpServletRequest request, @Valid @RequestBody RecommendJoinRequestDTO dto) @@ -62,7 +61,7 @@ public CommonApiResponse> getAllRecommends( } @PostMapping("/request") - @ApiOperation(value = "다른 유저에게 추천서 작성을 요청한다 (registerToken 필요)") + @ApiOperation(value = "다른 유저에게 추천서 작성을 요청한다 (RegisterToken)") public CommonApiResponse createRecommendRequest( HttpServletRequest request, @Valid @RequestBody RecommendRequestDTO dto) @@ -80,7 +79,7 @@ public CommonApiResponse createRecommendRequest( //제일 아래에 있어야함 @GetMapping("/{uuid}") - @ApiOperation(value = "추천 요청받은 uuid 를 가진 추천사 정보를 가져온다 (Register / AccessToken 필요)") + @ApiOperation(value = "추천 요청받은 uuid 를 가진 추천사 정보를 가져온다 (Register / AccessToken)") public CommonApiResponse getRecommendByUuid( HttpServletRequest request, @PathVariable("uuid") String uuid) @@ -93,16 +92,16 @@ public CommonApiResponse getRecommendByUuid( } @PatchMapping("/{uuid}/accept") - @ApiOperation(value = "요청받은 uuid 추천사에 자신을 추천인으로 등록한 후 임시 회원으로 가입한다 (Register 필요)") + @ApiOperation(value = "요청받은 uuid 추천사에 자신을 추천인으로 등록한 후 임시 회원으로 가입한다 (RegisterToken)") public CommonApiResponse updateRecommendByUuid( HttpServletRequest request, @PathVariable("uuid") String uuid, - @Valid @RequestBody RecommendAcceptRequestDTO dto) + @Valid @RequestBody RecommendAcceptWithJoinRequestDTO dto) { //토큰 장착 확인 String phone = jwtTokenService.parsePhoneByRegisterToken(request); - RecommendResponseDTO recommendResponseDTO = recommendService.updateRecommendRequest(uuid, phone, dto); + RecommendResponseDTO recommendResponseDTO = recommendService.updateRecommendRequestWithJoin(uuid, phone, dto); return CommonApiResponse.of(recommendResponseDTO); } } diff --git a/src/main/java/com/tikitaka/naechinso/domain/recommend/RecommendService.java b/src/main/java/com/tikitaka/naechinso/domain/recommend/RecommendService.java index ee17f03..5e7cb8d 100644 --- a/src/main/java/com/tikitaka/naechinso/domain/recommend/RecommendService.java +++ b/src/main/java/com/tikitaka/naechinso/domain/recommend/RecommendService.java @@ -1,6 +1,7 @@ package com.tikitaka.naechinso.domain.recommend; import com.tikitaka.naechinso.domain.member.MemberRepository; +import com.tikitaka.naechinso.domain.member.dto.MemberJobUpdateRequestDTO; import com.tikitaka.naechinso.domain.recommend.dto.RecommendMemberAcceptRequestDTO; import com.tikitaka.naechinso.domain.member.entity.Member; import com.tikitaka.naechinso.domain.recommend.dto.*; @@ -24,17 +25,18 @@ public class RecommendService { private final RecommendRepository recommendRepository; private final MemberRepository memberRepository; + /** + * 추천사 정보를 가져온다 + * */ public RecommendListResponseDTO readRecommendList(Member authMember) { Member member = memberRepository.findByPhone(authMember.getPhone()) .orElseThrow(() -> new NotFoundException(ErrorCode.USER_NOT_FOUND)); return RecommendListResponseDTO.of(member); } - public RecommendResponseDTO createRecommend(String senderPhone, RecommendResponseDTO dto) { - - return null; - } - + /** + * 임시회원으로 등록하며 가입하지 않은 임의의 유저 추천사를 작성한다 + * */ public RecommendResponseDTO createRecommendJoin(String senderPhone, RecommendJoinRequestDTO dto) { //멤버가 이미 있으면 종료 Optional checkSender = memberRepository.findByPhone(senderPhone); @@ -69,6 +71,7 @@ public RecommendResponseDTO createRecommendJoin(String senderPhone, RecommendJoi .receiverGender(dto.getReceiverGender()) .receiverMeet(dto.getMeet()) .receiverPersonality(dto.getPersonality()) + .receiverPeriod(dto.getPeriod()) .build(); memberRepository.save(sender); @@ -77,6 +80,9 @@ public RecommendResponseDTO createRecommendJoin(String senderPhone, RecommendJoi return RecommendResponseDTO.of(recommend); } + /** + * 내 추천사 작성을 요청한다 + * */ public RecommendResponseDTO createRecommendRequest(String receiverPhone, RecommendRequestDTO dto) { //이미 추천사 요청을 보냄 if (existsByReceiverPhone(receiverPhone)) { @@ -99,7 +105,10 @@ public RecommendResponseDTO createRecommendRequest(String receiverPhone, Recomme return RecommendResponseDTO.of(recommend); } - public RecommendResponseDTO updateRecommendRequest(String uuid, String senderPhone, RecommendAcceptRequestDTO dto) { + /** + * 임시회원으로 가입하며 해당 uuid 추천사에 자신을 등록한다 + * */ + public RecommendResponseDTO updateRecommendRequestWithJoin(String uuid, String senderPhone, RecommendAcceptWithJoinRequestDTO dto) { Recommend recommend = findByUuidAndReceiverNotNull(uuid); @@ -114,23 +123,14 @@ public RecommendResponseDTO updateRecommendRequest(String uuid, String senderPho } //유저가 없으면 회원가입 시킴, 있으면 그대로 사용 - Member sender = memberRepository.findByPhone(senderPhone) - .orElse(dto.toSender(senderPhone)); - - recommend.setSender(sender); - recommend.setSenderPhone(senderPhone); - recommend.setSenderName(dto.getName()); - recommend.setSenderAge(dto.getAge()); - recommend.setSenderGender(dto.getGender()); - recommend.setSenderJobName(dto.getJobName()); - recommend.setSenderJobPart(dto.getJobPart()); - recommend.setSenderJobLocation(dto.getJobLocation()); - recommend.setReceiverName(dto.getReceiverName()); - recommend.setReceiverAge(dto.getReceiverAge()); - recommend.setReceiverAppeal(dto.getAppeal()); - recommend.setReceiverGender(dto.getReceiverGender()); - recommend.setReceiverMeet(dto.getMeet()); - recommend.setReceiverPersonality(dto.getPersonality()); + Optional checkSender = memberRepository.findByPhone(senderPhone); + if(checkSender.isPresent()) { + throw new BadRequestException(ErrorCode.USER_ALREADY_EXIST); + } + Member sender = dto.toSender(senderPhone); + + //유저 정보 업데이트, 가입 정보가 이미 있다면 무시됨, 없으면 생성 + recommend.update(sender, dto); memberRepository.save(sender); recommendRepository.save(recommend); @@ -139,8 +139,7 @@ public RecommendResponseDTO updateRecommendRequest(String uuid, String senderPho } /** - * 추천사 작성 유저가 정회원일 경우 유저 정보로 추천사를 등록한다 - * + * 추천사 작성 유저가 정회원일 경우 해당 유저 정보로 uuid 에 해당하는 추천사를 등록한다 * */ public RecommendResponseDTO updateRecommendMemberAccept(String uuid, String senderPhone, RecommendMemberAcceptRequestDTO dto) { @@ -160,17 +159,54 @@ public RecommendResponseDTO updateRecommendMemberAccept(String uuid, String send Member sender = memberRepository.findByPhone(senderPhone) .orElseThrow(() -> new BadRequestException(ErrorCode.USER_NOT_FOUND)); - recommend.setSender(sender); - recommend.setSenderPhone(sender.getPhone()); - recommend.setSenderName(sender.getName()); - recommend.setSenderAge(sender.getAge()); - recommend.setSenderGender(sender.getGender()); - recommend.setSenderJobName(sender.getJobName()); - recommend.setSenderJobPart(sender.getJobPart()); - recommend.setSenderJobLocation(sender.getJobLocation()); - recommend.setReceiverAppeal(dto.getAppeal()); - recommend.setReceiverMeet(dto.getMeet()); - recommend.setReceiverPersonality(dto.getPersonality()); + recommend.update(sender, dto); + + memberRepository.save(sender); + recommendRepository.save(recommend); + + return RecommendResponseDTO.of(recommend); + } + + /** + * 추천사 작성 유저가 임시회원 이상일 경우 + * 해당 유저 정보로 uuid 에 해당하는 추천사를 등록하며 + * 직업 정보를 업데이트 한다 + * */ + public RecommendResponseDTO updateRecommendMemberAccept(String uuid, String senderPhone, RecommendMemberAcceptWithUpdateJobRequestDTO dto) { + + Recommend recommend = findByUuidAndReceiverNotNull(uuid); + + //자기 자신을 추천하면 종료 + if (senderPhone.equals(recommend.getReceiverPhone())) { + throw new BadRequestException(ErrorCode.CANNOT_RECOMMEND_MYSELF); + } + + //이미 작성된 추천사 엔티티면 종료 + if (recommend.getSender() != null) { + throw new BadRequestException(ErrorCode.RECOMMEND_SENDER_ALREADY_EXIST); + } + + //유저가 없으면 400 + Member sender = memberRepository.findByPhone(senderPhone) + .orElseThrow(() -> new BadRequestException(ErrorCode.USER_NOT_FOUND)); + + MemberJobUpdateRequestDTO updateDTO1 = MemberJobUpdateRequestDTO.builder() + .jobLocation(dto.getJobLocation()) + .jobPart(dto.getJobPart()) + .jobName(dto.getJobName()) + .build(); + + sender.setJob(updateDTO1); + + RecommendMemberAcceptRequestDTO updateDTO2 = RecommendMemberAcceptRequestDTO.builder() + .appeal(dto.getAppeal()) + .meet(dto.getMeet()) + .period(dto.getPeriod()) + .personality(dto.getPersonality()) + .build(); + + recommend.update(sender, updateDTO2); + memberRepository.save(sender); recommendRepository.save(recommend); diff --git a/src/main/java/com/tikitaka/naechinso/domain/recommend/dto/RecommendAcceptRequestDTO.java b/src/main/java/com/tikitaka/naechinso/domain/recommend/dto/RecommendAcceptWithJoinRequestDTO.java similarity index 95% rename from src/main/java/com/tikitaka/naechinso/domain/recommend/dto/RecommendAcceptRequestDTO.java rename to src/main/java/com/tikitaka/naechinso/domain/recommend/dto/RecommendAcceptWithJoinRequestDTO.java index 51c2d96..1fe211c 100644 --- a/src/main/java/com/tikitaka/naechinso/domain/recommend/dto/RecommendAcceptRequestDTO.java +++ b/src/main/java/com/tikitaka/naechinso/domain/recommend/dto/RecommendAcceptWithJoinRequestDTO.java @@ -13,7 +13,7 @@ @Getter @Builder @ToString -public class RecommendAcceptRequestDTO { +public class RecommendAcceptWithJoinRequestDTO { @ApiModelProperty(example = "닉") @NotBlank(message = "이름을 입력해주세요") private String name; @@ -83,6 +83,9 @@ public class RecommendAcceptRequestDTO { @NotBlank(message = "친구의 매력을 입력해주세요") private String appeal; + @ApiModelProperty(example = "1년") + @NotBlank(message = "만난 기간을 입력해주세요") + private String period; public Member toSender(String phone){ return Member.builder() diff --git a/src/main/java/com/tikitaka/naechinso/domain/recommend/dto/RecommendJoinRequestDTO.java b/src/main/java/com/tikitaka/naechinso/domain/recommend/dto/RecommendJoinRequestDTO.java index 5d294df..e12e67d 100644 --- a/src/main/java/com/tikitaka/naechinso/domain/recommend/dto/RecommendJoinRequestDTO.java +++ b/src/main/java/com/tikitaka/naechinso/domain/recommend/dto/RecommendJoinRequestDTO.java @@ -2,6 +2,7 @@ import com.tikitaka.naechinso.domain.member.constant.Gender; import com.tikitaka.naechinso.domain.member.entity.Member; +import com.tikitaka.naechinso.domain.recommend.entity.Recommend; import com.tikitaka.naechinso.global.annotation.Enum; import io.swagger.annotations.ApiModelProperty; import lombok.*; @@ -92,6 +93,9 @@ public class RecommendJoinRequestDTO { @NotBlank(message = "친구의 매력을 입력해주세요") private String appeal; + @ApiModelProperty(example = "1년") + @NotBlank(message = "만난 기간을 입력해주세요") + private String period; public Member toSender(String phone){ return Member.builder() diff --git a/src/main/java/com/tikitaka/naechinso/domain/recommend/dto/RecommendMemberAcceptRequestDTO.java b/src/main/java/com/tikitaka/naechinso/domain/recommend/dto/RecommendMemberAcceptRequestDTO.java index 31a6d08..b74575c 100644 --- a/src/main/java/com/tikitaka/naechinso/domain/recommend/dto/RecommendMemberAcceptRequestDTO.java +++ b/src/main/java/com/tikitaka/naechinso/domain/recommend/dto/RecommendMemberAcceptRequestDTO.java @@ -25,4 +25,8 @@ public class RecommendMemberAcceptRequestDTO { @ApiModelProperty(example = "짱") @NotBlank(message = "친구의 매력을 입력해주세요") private String appeal; + + @ApiModelProperty(example = "1년") + @NotBlank(message = "만난 기간을 입력해주세요") + private String period; } diff --git a/src/main/java/com/tikitaka/naechinso/domain/recommend/dto/RecommendMemberAcceptWithUpdateJobRequestDTO.java b/src/main/java/com/tikitaka/naechinso/domain/recommend/dto/RecommendMemberAcceptWithUpdateJobRequestDTO.java new file mode 100644 index 0000000..46e5f08 --- /dev/null +++ b/src/main/java/com/tikitaka/naechinso/domain/recommend/dto/RecommendMemberAcceptWithUpdateJobRequestDTO.java @@ -0,0 +1,45 @@ +package com.tikitaka.naechinso.domain.recommend.dto; + +import com.tikitaka.naechinso.domain.member.constant.Gender; +import com.tikitaka.naechinso.domain.member.entity.Member; +import com.tikitaka.naechinso.global.annotation.Enum; +import io.swagger.annotations.ApiModelProperty; +import lombok.*; + +import javax.validation.constraints.*; + +@AllArgsConstructor +@NoArgsConstructor +@Getter +@Builder +@ToString +public class RecommendMemberAcceptWithUpdateJobRequestDTO { + @ApiModelProperty(example = "카카오") + @NotBlank(message = "직장명을 입력해주세요") + private String jobName; + + @ApiModelProperty(example = "개발자") + @NotBlank(message = "직장 부서를 입력해주세요") + private String jobPart; + + @ApiModelProperty(example = "판교") + @NotBlank(message = "직장 위치를 입력해주세요") + private String jobLocation; + + @ApiModelProperty(example = "CMC 에서") + @NotBlank(message = "만나게 된 계기를 입력해주세요") + private String meet; + + @ApiModelProperty(example = "최고") + @NotBlank(message = "친구의 성격 키워드를 입력해주세요") + private String personality; + + @ApiModelProperty(example = "짱") + @NotBlank(message = "친구의 매력을 입력해주세요") + private String appeal; + + @ApiModelProperty(example = "1년") + @NotBlank(message = "만난 기간을 입력해주세요") + private String period; + +} diff --git a/src/main/java/com/tikitaka/naechinso/domain/recommend/dto/RecommendResponseDTO.java b/src/main/java/com/tikitaka/naechinso/domain/recommend/dto/RecommendResponseDTO.java index a5189e6..5a8ea66 100644 --- a/src/main/java/com/tikitaka/naechinso/domain/recommend/dto/RecommendResponseDTO.java +++ b/src/main/java/com/tikitaka/naechinso/domain/recommend/dto/RecommendResponseDTO.java @@ -23,6 +23,8 @@ public class RecommendResponseDTO { private String appeal; + private String period; + private Long senderId; private Long receiverId; @@ -52,6 +54,7 @@ public static RecommendResponseDTO of(Recommend recommend) { .gender(recommend.getReceiverGender()) .meet(recommend.getReceiverMeet()) .appeal(recommend.getReceiverAppeal()) + .period(recommend.getReceiverPeriod()) .build(); } } diff --git a/src/main/java/com/tikitaka/naechinso/domain/recommend/entity/Recommend.java b/src/main/java/com/tikitaka/naechinso/domain/recommend/entity/Recommend.java index ca4fe1d..794a8a4 100644 --- a/src/main/java/com/tikitaka/naechinso/domain/recommend/entity/Recommend.java +++ b/src/main/java/com/tikitaka/naechinso/domain/recommend/entity/Recommend.java @@ -3,10 +3,10 @@ import com.fasterxml.jackson.annotation.JsonIgnore; import com.tikitaka.naechinso.domain.member.constant.Gender; import com.tikitaka.naechinso.domain.member.entity.Member; -import com.tikitaka.naechinso.domain.recommend.dto.RecommendJoinRequestDTO; +import com.tikitaka.naechinso.domain.recommend.dto.RecommendAcceptWithJoinRequestDTO; +import com.tikitaka.naechinso.domain.recommend.dto.RecommendMemberAcceptRequestDTO; import com.tikitaka.naechinso.global.config.entity.BaseEntity; import lombok.*; -import org.hibernate.annotations.GenericGenerator; import javax.persistence.*; import java.util.UUID; @@ -60,6 +60,7 @@ public class Recommend extends BaseEntity { @Column(name = "mem_job_location") private String senderJobLocation; + /* 받는 사람이 아직 가입 안했으면 NULL 일수도 있음 */ @ManyToOne(fetch = FetchType.LAZY) @JsonIgnore @@ -88,4 +89,38 @@ public class Recommend extends BaseEntity { @Column(name = "rec_appeal") private String receiverAppeal; + @Column(name = "rec_period") + private String receiverPeriod; + + public void update(Member sender, RecommendAcceptWithJoinRequestDTO requestDTO) { + updateSender(sender); + updateReceiver(requestDTO); + } + + public void update(Member sender, RecommendMemberAcceptRequestDTO requestDTO) { + updateSender(sender); + this.receiverAppeal = requestDTO.getAppeal(); + this.receiverMeet = requestDTO.getMeet(); + this.receiverPersonality = requestDTO.getPersonality(); + this.receiverPeriod = requestDTO.getPeriod(); + } + + public void updateSender(Member sender) { + this.sender = sender; + this.senderPhone = sender.getPhone(); + this.senderName = sender.getName(); + this.senderAge = sender.getAge(); + this.senderGender = sender.getGender(); + this.senderJobName = sender.getJobName(); + this.senderJobPart = sender.getJobPart(); + this.senderJobLocation = sender.getJobLocation(); + } + + public void updateReceiver(RecommendAcceptWithJoinRequestDTO requestDTO) { + this.receiverAppeal = requestDTO.getAppeal(); + this.receiverMeet = requestDTO.getMeet(); + this.receiverPersonality = requestDTO.getPersonality(); + this.receiverPeriod = requestDTO.getPeriod(); + } + } From bfc7a2b63730e9d9ea881fb3e122e73a6634b88b Mon Sep 17 00:00:00 2001 From: gengminy Date: Thu, 6 Oct 2022 13:47:12 +0900 Subject: [PATCH 14/72] =?UTF-8?q?:hammer:=20fix(prod):=20HealthCheckContro?= =?UTF-8?q?ller=20=EC=84=A4=EC=A0=95=20#5?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../java/com/tikitaka/naechinso/domain/MainController.java | 4 ++-- .../naechinso/global/config/security/SecurityConfig.java | 1 + 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/src/main/java/com/tikitaka/naechinso/domain/MainController.java b/src/main/java/com/tikitaka/naechinso/domain/MainController.java index 9044b95..160661b 100644 --- a/src/main/java/com/tikitaka/naechinso/domain/MainController.java +++ b/src/main/java/com/tikitaka/naechinso/domain/MainController.java @@ -12,8 +12,8 @@ @RestController @RequiredArgsConstructor public class MainController { - @GetMapping("/") - public CommonApiResponse rootEndPoint() { + @GetMapping + public CommonApiResponse healthCheck() { return CommonApiResponse.of(true); } } diff --git a/src/main/java/com/tikitaka/naechinso/global/config/security/SecurityConfig.java b/src/main/java/com/tikitaka/naechinso/global/config/security/SecurityConfig.java index f9a388c..361cc23 100644 --- a/src/main/java/com/tikitaka/naechinso/global/config/security/SecurityConfig.java +++ b/src/main/java/com/tikitaka/naechinso/global/config/security/SecurityConfig.java @@ -60,6 +60,7 @@ public SecurityFilterChain filterChain(HttpSecurity http) throws Exception { .antMatchers("/admin/**").hasAuthority("ROLE_ADMIN") .antMatchers("/member/login").permitAll() .antMatchers("/member/join").permitAll() + .antMatchers("/").permitAll() //health check .antMatchers("/sms/**").permitAll() .antMatchers(HttpMethod.POST, "/recommend").permitAll() .antMatchers("/recommend/**").permitAll() From 05298602176d0d0365fdcc7f165d4c2b6a6490e5 Mon Sep 17 00:00:00 2001 From: gengminy Date: Thu, 6 Oct 2022 14:50:34 +0900 Subject: [PATCH 15/72] =?UTF-8?q?:hammer:=20fix(user):=20=ED=95=99?= =?UTF-8?q?=EB=A0=A5=20=ED=95=84=EB=93=9C=20Member=20=EB=A1=9C=20=EC=9D=B4?= =?UTF-8?q?=EB=8F=99=20=EB=B0=8F=20url=20=EC=B6=94=EA=B0=80=20#20?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- ...roller.java => HealthCheckController.java} | 5 +- .../domain/member/MemberController.java | 84 ++++++++----------- .../domain/member/MemberService.java | 27 +++++- .../dto/MemberCommonJoinRequestDTO.java | 15 ++++ .../member/dto/MemberDetailResponseDTO.java | 11 --- .../member/dto/MemberEduUpdateRequestDTO.java | 29 +++++++ .../domain/member/entity/Member.java | 18 +++- .../domain/member/entity/MemberDetail.java | 15 ---- .../domain/recommend/RecommendService.java | 2 +- 9 files changed, 126 insertions(+), 80 deletions(-) rename src/main/java/com/tikitaka/naechinso/domain/{MainController.java => HealthCheckController.java} (74%) create mode 100644 src/main/java/com/tikitaka/naechinso/domain/member/dto/MemberEduUpdateRequestDTO.java diff --git a/src/main/java/com/tikitaka/naechinso/domain/MainController.java b/src/main/java/com/tikitaka/naechinso/domain/HealthCheckController.java similarity index 74% rename from src/main/java/com/tikitaka/naechinso/domain/MainController.java rename to src/main/java/com/tikitaka/naechinso/domain/HealthCheckController.java index 160661b..4be24f1 100644 --- a/src/main/java/com/tikitaka/naechinso/domain/MainController.java +++ b/src/main/java/com/tikitaka/naechinso/domain/HealthCheckController.java @@ -1,17 +1,14 @@ package com.tikitaka.naechinso.domain; -import com.tikitaka.naechinso.domain.sms.dto.SmsVerificationCodeRequestDTO; import com.tikitaka.naechinso.global.config.CommonApiResponse; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; import org.springframework.web.bind.annotation.*; -import javax.validation.Valid; - @Slf4j @RestController @RequiredArgsConstructor -public class MainController { +public class HealthCheckController { @GetMapping public CommonApiResponse healthCheck() { return CommonApiResponse.of(true); diff --git a/src/main/java/com/tikitaka/naechinso/domain/member/MemberController.java b/src/main/java/com/tikitaka/naechinso/domain/member/MemberController.java index d34b836..a9a622e 100644 --- a/src/main/java/com/tikitaka/naechinso/domain/member/MemberController.java +++ b/src/main/java/com/tikitaka/naechinso/domain/member/MemberController.java @@ -34,11 +34,9 @@ public class MemberController { @GetMapping @ApiOperation(value = "유저 자신의 모든 정보를 가져온다 (AccessToken)") public CommonApiResponse getMyInformation( - HttpServletRequest request, @ApiIgnore @AuthMember Member member) { - //로그인 상태가 아닌 경우 401 - if (member == null) { - throw new UnauthorizedException(ErrorCode.UNAUTHORIZED_USER); - } + HttpServletRequest request, + @ApiIgnore @AuthMember Member member + ) { return CommonApiResponse.of(MemberCommonResponseDTO.of(member)); } @@ -60,12 +58,8 @@ public CommonApiResponse getMyInformation( @GetMapping("/detail") @ApiOperation(value = "회원가입 세부 정보를 가져온다 (AccessToken 필요)") public CommonApiResponse getMemberDetail( - @ApiIgnore @AuthMember Member member) - { - //로그인 상태가 아닌 경우 401 - if (member == null) { - throw new UnauthorizedException(ErrorCode.UNAUTHORIZED_USER); - } + @ApiIgnore @AuthMember Member member + ) { final MemberDetailResponseDTO res = memberService.readDetail(member); return CommonApiResponse.of(res); } @@ -74,23 +68,27 @@ public CommonApiResponse getMemberDetail( @ApiOperation(value = "직업 정보를 업데이트 한다 (AccessToken)") public CommonApiResponse setMemberJob( @RequestBody MemberJobUpdateRequestDTO dto, - @ApiIgnore @AuthMember Member member) - { - //로그인 상태가 아닌 경우 401 - if (member == null) { - throw new UnauthorizedException(ErrorCode.UNAUTHORIZED_USER); - } + @ApiIgnore @AuthMember Member member + ) { return CommonApiResponse.of(memberService.updateJob(member, dto)); } + @PatchMapping("/edu") + @ApiOperation(value = "학력 정보를 업데이트 한다 (AccessToken)") + public CommonApiResponse setMemberJob( + @RequestBody MemberEduUpdateRequestDTO dto, + @ApiIgnore @AuthMember Member member + ) { + return CommonApiResponse.of(memberService.updateEdu(member, dto)); + } + @PostMapping("/join") @ApiOperation(value = "유저를 공통 정보로 가입시킨다 (RegisterToken)") public CommonApiResponse join( HttpServletRequest request, @Valid @RequestBody MemberDetailJoinRequestDTO dto - ) - { + ) { return null; // //로그인 상태가 아닌 경우 401 // if (member == null) { @@ -105,12 +103,8 @@ public CommonApiResponse join( @ApiOperation(value = "회원가입 세부 정보를 입력하여 최종 가입시킨다 (AccessToken)") public CommonApiResponse setMemberDetail( @Valid @RequestBody MemberDetailJoinRequestDTO dto, - @ApiIgnore @AuthMember Member member) - { - //로그인 상태가 아닌 경우 401 - if (member == null) { - throw new UnauthorizedException(ErrorCode.UNAUTHORIZED_USER); - } + @ApiIgnore @AuthMember Member member + ) { final MemberDetailResponseDTO res = memberService.createDetail(member, dto); return CommonApiResponse.of(res); } @@ -118,7 +112,10 @@ public CommonApiResponse setMemberDetail( //페이징 처리 추가할 예정 @GetMapping("/find") @ApiOperation(value = "[Admin]현재 가입한 모든 유저를 불러온다 (AccessToken)") - public CommonApiResponse> getMyInformation() { + public CommonApiResponse> getMyInformation( +// @RequestBody RecommendMemberAcceptRequestDTO dto, +// @ApiIgnore @AuthMember Member member + ) { return CommonApiResponse.of(memberService.findAll()); } @@ -126,12 +123,10 @@ public CommonApiResponse> getMyInformation() { @ApiOperation(value = "다른 유저의 추천사를 작성한다 (AccessToken)") public CommonApiResponse createRecommend( @RequestBody RecommendMemberAcceptRequestDTO dto, - @ApiIgnore @AuthMember Member member) - { + @ApiIgnore @AuthMember Member member + ) { //로그인 상태가 아닌 경우 401 - if (member == null) { - throw new UnauthorizedException(ErrorCode.UNAUTHORIZED_USER); - } + memberService.validateLoggedIn(member); return CommonApiResponse.of(null); } @@ -144,15 +139,10 @@ public CommonApiResponse createRecommend( public CommonApiResponse updateRecommendByUuid( @PathVariable("uuid") String uuid, @Valid @RequestBody RecommendMemberAcceptWithUpdateJobRequestDTO dto, - @ApiIgnore @AuthMember Member member) - { + @ApiIgnore @AuthMember Member member + ) { //로그인 상태가 아닌 경우 401 - if (member == null) { - throw new UnauthorizedException(ErrorCode.UNAUTHORIZED_USER); - } - if (member.getDetail() == null) { - throw new UnauthorizedException(ErrorCode.FORBIDDEN_USER); - } + memberService.validateFormalMember(member); String phone = member.getPhone(); RecommendResponseDTO recommendResponseDTO = recommendService.updateRecommendMemberAccept(uuid, phone, dto); return CommonApiResponse.of(recommendResponseDTO); @@ -167,17 +157,17 @@ public CommonApiResponse updateRecommendByUuid( public CommonApiResponse updateRecommendByUuidWithJob( @PathVariable("uuid") String uuid, @Valid @RequestBody RecommendMemberAcceptWithUpdateJobRequestDTO dto, - @ApiIgnore @AuthMember Member member) - { + @ApiIgnore @AuthMember Member member + ) { //로그인 상태가 아닌 경우 401 - if (member == null) { - throw new UnauthorizedException(ErrorCode.UNAUTHORIZED_USER); - } - if (member.getDetail() == null) { - throw new UnauthorizedException(ErrorCode.FORBIDDEN_USER); - } + memberService.validateFormalMember(member); String phone = member.getPhone(); RecommendResponseDTO recommendResponseDTO = recommendService.updateRecommendMemberAccept(uuid, phone, dto); return CommonApiResponse.of(recommendResponseDTO); } + + /** + * @// TODO: 2022/10/06 인증정보 업데이트 방식 정할것. 직업 또는 학생 둘다 가능하기 떄문 + * */ + } diff --git a/src/main/java/com/tikitaka/naechinso/domain/member/MemberService.java b/src/main/java/com/tikitaka/naechinso/domain/member/MemberService.java index dcd8c60..a3042c4 100644 --- a/src/main/java/com/tikitaka/naechinso/domain/member/MemberService.java +++ b/src/main/java/com/tikitaka/naechinso/domain/member/MemberService.java @@ -10,6 +10,7 @@ import com.tikitaka.naechinso.global.error.ErrorCode; import com.tikitaka.naechinso.global.error.exception.BadRequestException; import com.tikitaka.naechinso.global.error.exception.NotFoundException; +import com.tikitaka.naechinso.global.error.exception.UnauthorizedException; import lombok.RequiredArgsConstructor; import org.springframework.security.authentication.UsernamePasswordAuthenticationToken; import org.springframework.security.core.authority.SimpleGrantedAuthority; @@ -100,9 +101,33 @@ public MemberCommonResponseDTO updateJob(Member authMember, MemberJobUpdateReque Member member = memberRepository.findById(authMember.getId()) .orElseThrow(() -> new NotFoundException(ErrorCode.USER_NOT_FOUND)); - member.setJob(dto); + member.updateJob(dto); memberRepository.save(member); return MemberCommonResponseDTO.of(member); } + public MemberCommonResponseDTO updateEdu(Member authMember, MemberEduUpdateRequestDTO dto){ + //영속성 유지를 위한 fetch + Member member = memberRepository.findById(authMember.getId()) + .orElseThrow(() -> new NotFoundException(ErrorCode.USER_NOT_FOUND)); + + member.updateEdu(dto); + memberRepository.save(member); + return MemberCommonResponseDTO.of(member); + } + + + public void validateLoggedIn(Member authMember) { + if (authMember == null) { + throw new UnauthorizedException(ErrorCode.UNAUTHORIZED_USER); + } + } + + public void validateFormalMember(Member authMember) { + validateLoggedIn(authMember); + if (authMember.getDetail() == null) { + throw new UnauthorizedException(ErrorCode.FORBIDDEN_USER); + } + } + } diff --git a/src/main/java/com/tikitaka/naechinso/domain/member/dto/MemberCommonJoinRequestDTO.java b/src/main/java/com/tikitaka/naechinso/domain/member/dto/MemberCommonJoinRequestDTO.java index 298bab5..06b10d9 100644 --- a/src/main/java/com/tikitaka/naechinso/domain/member/dto/MemberCommonJoinRequestDTO.java +++ b/src/main/java/com/tikitaka/naechinso/domain/member/dto/MemberCommonJoinRequestDTO.java @@ -66,6 +66,18 @@ public class MemberCommonJoinRequestDTO { @NotBlank(message = "직장 위치를 입력해주세요") private String jobLocation; + @ApiModelProperty(example = "서울") + @NotBlank(message = "학교명을 입력해주세요") + private String eduName; + + @ApiModelProperty(example = "컴퓨터공학과") + @NotBlank(message = "전공을 입력해주세요") + private String eduMajor; + + @ApiModelProperty(example = "대학교") + @NotBlank(message = "최종학력을 입력해주세요") + private String eduLevel; + public static Member toCommonMember(MemberCommonJoinRequestDTO dto) { Member member = Member.builder() .phone(dto.phone) @@ -80,6 +92,9 @@ public static Member toCommonMember(MemberCommonJoinRequestDTO dto) { .jobName(dto.jobName) .jobPart(dto.jobPart) .jobLocation(dto.jobLocation) + .eduName(dto.eduName) + .eduMajor(dto.eduMajor) + .eduLevel(dto.eduLevel) .build(); return member; diff --git a/src/main/java/com/tikitaka/naechinso/domain/member/dto/MemberDetailResponseDTO.java b/src/main/java/com/tikitaka/naechinso/domain/member/dto/MemberDetailResponseDTO.java index 9391403..8203075 100644 --- a/src/main/java/com/tikitaka/naechinso/domain/member/dto/MemberDetailResponseDTO.java +++ b/src/main/java/com/tikitaka/naechinso/domain/member/dto/MemberDetailResponseDTO.java @@ -30,8 +30,6 @@ public class MemberDetailResponseDTO { private int age; - - private int height; private String address; @@ -56,12 +54,6 @@ public class MemberDetailResponseDTO { private Long point; - private String school; - - private String major; - - private String eduLevel; - public static MemberDetailResponseDTO of(Member member) { MemberDetail detail = member.getDetail(); //회원가입 정보가 없으면 null @@ -105,9 +97,6 @@ private static MemberDetailResponseDTO buildDetail(MemberDetail detail) { .style(detail.getStyle()) .picture(detail.getPicture()) .point(detail.getPoint()) - .school(detail.getSchool()) - .major(detail.getMajor()) - .eduLevel(detail.getEduLevel()) .build(); } diff --git a/src/main/java/com/tikitaka/naechinso/domain/member/dto/MemberEduUpdateRequestDTO.java b/src/main/java/com/tikitaka/naechinso/domain/member/dto/MemberEduUpdateRequestDTO.java new file mode 100644 index 0000000..21f510b --- /dev/null +++ b/src/main/java/com/tikitaka/naechinso/domain/member/dto/MemberEduUpdateRequestDTO.java @@ -0,0 +1,29 @@ +package com.tikitaka.naechinso.domain.member.dto; + +import io.swagger.annotations.ApiModelProperty; +import lombok.*; + +import javax.validation.constraints.NotBlank; + +/** + * 직업 정보 업데이트를 위한 DTO + * @author gengminy 221005 + * */ +@AllArgsConstructor +@NoArgsConstructor +@Getter +@Builder +@ToString +public class MemberEduUpdateRequestDTO { + @ApiModelProperty(example = "서울") + @NotBlank(message = "학교명을 입력해주세요") + private String eduName; + + @ApiModelProperty(example = "컴퓨터공학과") + @NotBlank(message = "전공을 입력해주세요") + private String eduMajor; + + @ApiModelProperty(example = "대학교") + @NotBlank(message = "최종학력을 입력해주세요") + private String eduLevel; +} diff --git a/src/main/java/com/tikitaka/naechinso/domain/member/entity/Member.java b/src/main/java/com/tikitaka/naechinso/domain/member/entity/Member.java index 057259b..9527aad 100644 --- a/src/main/java/com/tikitaka/naechinso/domain/member/entity/Member.java +++ b/src/main/java/com/tikitaka/naechinso/domain/member/entity/Member.java @@ -3,6 +3,7 @@ import com.fasterxml.jackson.annotation.JsonIgnore; import com.tikitaka.naechinso.domain.member.constant.Gender; import com.tikitaka.naechinso.domain.member.constant.Role; +import com.tikitaka.naechinso.domain.member.dto.MemberEduUpdateRequestDTO; import com.tikitaka.naechinso.domain.member.dto.MemberJobUpdateRequestDTO; import com.tikitaka.naechinso.domain.recommend.entity.Recommend; import com.tikitaka.naechinso.global.config.entity.BaseEntity; @@ -78,6 +79,15 @@ public class Member extends BaseEntity { @Column(name = "mem_job_location") private String jobLocation; + @Column(name = "mem_school") + private String eduName; + + @Column(name = "mem_major") + private String eduMajor; + + @Column(name = "mem_edu_level") + private String eduLevel; + //가입했을 경우 정보 디테일 @OneToOne(mappedBy = "member") @JoinColumn(name = "mem_detail") @@ -99,9 +109,15 @@ public void setDetail(MemberDetail memberDetail) { this.detail = memberDetail; } - public void setJob(MemberJobUpdateRequestDTO requestDTO) { + public void updateJob(MemberJobUpdateRequestDTO requestDTO) { this.jobName = requestDTO.getJobName(); this.jobLocation = requestDTO.getJobLocation(); this.jobPart = requestDTO.getJobPart(); } + + public void updateEdu(MemberEduUpdateRequestDTO requestDTO) { + this.eduName = requestDTO.getEduName(); + this.eduMajor = requestDTO.getEduMajor(); + this.eduLevel = requestDTO.getEduLevel(); + } } diff --git a/src/main/java/com/tikitaka/naechinso/domain/member/entity/MemberDetail.java b/src/main/java/com/tikitaka/naechinso/domain/member/entity/MemberDetail.java index 1369af4..30a22c2 100644 --- a/src/main/java/com/tikitaka/naechinso/domain/member/entity/MemberDetail.java +++ b/src/main/java/com/tikitaka/naechinso/domain/member/entity/MemberDetail.java @@ -74,15 +74,6 @@ public class MemberDetail extends BaseEntity { @Builder.Default private Long point = 0L; - @Column(name = "mem_school") - private String school; - - @Column(name = "mem_major") - private String major; - - @Column(name = "mem_edu_level") - private String eduLevel; - // 포인트 내역 @OneToMany(mappedBy = "member") private List points = new ArrayList<>(); @@ -110,9 +101,6 @@ public static MemberDetail of(MemberDetailJoinRequestDTO dto) { .hobby(dto.getHobby()) .style(dto.getStyle()) .picture(dto.getPicture()) - .school(dto.getSchool()) - .major(dto.getMajor()) - .eduLevel(dto.getEduLevel()) .build(); } @@ -129,9 +117,6 @@ public static MemberDetail of(Member member, MemberDetailJoinRequestDTO dto) { .hobby(dto.getHobby()) .style(dto.getStyle()) .picture(dto.getPicture()) - .school(dto.getSchool()) - .major(dto.getMajor()) - .eduLevel(dto.getEduLevel()) .member(member) .build(); } diff --git a/src/main/java/com/tikitaka/naechinso/domain/recommend/RecommendService.java b/src/main/java/com/tikitaka/naechinso/domain/recommend/RecommendService.java index 5e7cb8d..dfdabfa 100644 --- a/src/main/java/com/tikitaka/naechinso/domain/recommend/RecommendService.java +++ b/src/main/java/com/tikitaka/naechinso/domain/recommend/RecommendService.java @@ -196,7 +196,7 @@ public RecommendResponseDTO updateRecommendMemberAccept(String uuid, String send .jobName(dto.getJobName()) .build(); - sender.setJob(updateDTO1); + sender.updateJob(updateDTO1); RecommendMemberAcceptRequestDTO updateDTO2 = RecommendMemberAcceptRequestDTO.builder() .appeal(dto.getAppeal()) From 1811a290491606e42ee09800a9c7e0913912e73b Mon Sep 17 00:00:00 2001 From: gengminy Date: Thu, 6 Oct 2022 20:10:38 +0900 Subject: [PATCH 16/72] =?UTF-8?q?:hammer:=20fix(rec):=20=EC=B6=94=EC=B2=9C?= =?UTF-8?q?=20dto=20=EC=88=98=EC=A0=95=20#20?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../domain/member/MemberController.java | 28 +++++++--- .../dto/MemberCommonJoinRequestDTO.java | 9 +++ .../member/dto/MemberCommonResponseDTO.java | 23 ++++++++ .../member/dto/MemberEduUpdateRequestDTO.java | 4 ++ .../member/dto/MemberJobUpdateRequestDTO.java | 4 ++ .../domain/member/entity/Member.java | 23 ++++++++ .../domain/recommend/RecommendController.java | 4 +- .../domain/recommend/RecommendService.java | 50 +++++++++-------- ...O.java => RecommendAndJoinRequestDTO.java} | 55 +++++++++++++------ ...mmendMemberAcceptAndUpdateRequestDTO.java} | 36 +++++++----- 10 files changed, 168 insertions(+), 68 deletions(-) rename src/main/java/com/tikitaka/naechinso/domain/recommend/dto/{RecommendJoinRequestDTO.java => RecommendAndJoinRequestDTO.java} (74%) rename src/main/java/com/tikitaka/naechinso/domain/recommend/dto/{RecommendMemberAcceptWithUpdateJobRequestDTO.java => RecommendMemberAcceptAndUpdateRequestDTO.java} (52%) diff --git a/src/main/java/com/tikitaka/naechinso/domain/member/MemberController.java b/src/main/java/com/tikitaka/naechinso/domain/member/MemberController.java index a9a622e..ed7561b 100644 --- a/src/main/java/com/tikitaka/naechinso/domain/member/MemberController.java +++ b/src/main/java/com/tikitaka/naechinso/domain/member/MemberController.java @@ -4,13 +4,11 @@ import com.tikitaka.naechinso.domain.member.entity.Member; import com.tikitaka.naechinso.domain.recommend.RecommendService; import com.tikitaka.naechinso.domain.recommend.dto.RecommendMemberAcceptRequestDTO; -import com.tikitaka.naechinso.domain.recommend.dto.RecommendMemberAcceptWithUpdateJobRequestDTO; +import com.tikitaka.naechinso.domain.recommend.dto.RecommendMemberAcceptAndUpdateRequestDTO; import com.tikitaka.naechinso.domain.recommend.dto.RecommendResponseDTO; import com.tikitaka.naechinso.global.annotation.AuthMember; import com.tikitaka.naechinso.global.config.CommonApiResponse; import com.tikitaka.naechinso.global.config.security.jwt.JwtTokenProvider; -import com.tikitaka.naechinso.global.error.ErrorCode; -import com.tikitaka.naechinso.global.error.exception.UnauthorizedException; import io.swagger.annotations.ApiOperation; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; @@ -138,7 +136,7 @@ public CommonApiResponse createRecommend( @ApiOperation(value = "요청받은 uuid 추천사에 자신을 추천인으로 등록한다 (AccessToken)") public CommonApiResponse updateRecommendByUuid( @PathVariable("uuid") String uuid, - @Valid @RequestBody RecommendMemberAcceptWithUpdateJobRequestDTO dto, + @Valid @RequestBody RecommendMemberAcceptAndUpdateRequestDTO dto, @ApiIgnore @AuthMember Member member ) { //로그인 상태가 아닌 경우 401 @@ -150,13 +148,13 @@ public CommonApiResponse updateRecommendByUuid( /** - * 직업 정보가 없을 경우 내 직업 정보를 업데이트하고 추천인을 가입시킨다 + * 직업 인증으로 추천인을 가입시킨다 * */ @PatchMapping("/recommend/{uuid}/accept/job") @ApiOperation(value = "요청받은 uuid 추천사에 자신을 추천인으로 등록하며 직업 정보를 업데이트 한다 (AccessToken)") - public CommonApiResponse updateRecommendByUuidWithJob( + public CommonApiResponse updateRecommendByUuidAndJob( @PathVariable("uuid") String uuid, - @Valid @RequestBody RecommendMemberAcceptWithUpdateJobRequestDTO dto, + @Valid @RequestBody RecommendMemberAcceptAndUpdateRequestDTO dto, @ApiIgnore @AuthMember Member member ) { //로그인 상태가 아닌 경우 401 @@ -167,7 +165,19 @@ public CommonApiResponse updateRecommendByUuidWithJob( } /** - * @// TODO: 2022/10/06 인증정보 업데이트 방식 정할것. 직업 또는 학생 둘다 가능하기 떄문 + * 학교 인증으로 추천인을 가입시킨다 * */ - + @PatchMapping("/recommend/{uuid}/accept/edu") + @ApiOperation(value = "요청받은 uuid 추천사에 자신을 추천인으로 등록하며 학교 정보를 업데이트 한다 (AccessToken)") + public CommonApiResponse updateRecommendByUuidAndEdu( + @PathVariable("uuid") String uuid, + @Valid @RequestBody RecommendMemberAcceptAndUpdateRequestDTO dto, + @ApiIgnore @AuthMember Member member + ) { + //로그인 상태가 아닌 경우 401 + memberService.validateFormalMember(member); + String phone = member.getPhone(); + RecommendResponseDTO recommendResponseDTO = recommendService.updateRecommendMemberAccept(uuid, phone, dto); + return CommonApiResponse.of(recommendResponseDTO); + } } diff --git a/src/main/java/com/tikitaka/naechinso/domain/member/dto/MemberCommonJoinRequestDTO.java b/src/main/java/com/tikitaka/naechinso/domain/member/dto/MemberCommonJoinRequestDTO.java index 06b10d9..6859cf9 100644 --- a/src/main/java/com/tikitaka/naechinso/domain/member/dto/MemberCommonJoinRequestDTO.java +++ b/src/main/java/com/tikitaka/naechinso/domain/member/dto/MemberCommonJoinRequestDTO.java @@ -66,6 +66,9 @@ public class MemberCommonJoinRequestDTO { @NotBlank(message = "직장 위치를 입력해주세요") private String jobLocation; + @ApiModelProperty(example = "인증 사진 링크") + @NotBlank(message = "인증 사진을 업로드 해주세요") + private String jobPicture; @ApiModelProperty(example = "서울") @NotBlank(message = "학교명을 입력해주세요") private String eduName; @@ -78,6 +81,10 @@ public class MemberCommonJoinRequestDTO { @NotBlank(message = "최종학력을 입력해주세요") private String eduLevel; + @ApiModelProperty(example = "인증 사진 링크") + @NotBlank(message = "인증 사진을 업로드 해주세요") + private String eduPicture; + public static Member toCommonMember(MemberCommonJoinRequestDTO dto) { Member member = Member.builder() .phone(dto.phone) @@ -92,9 +99,11 @@ public static Member toCommonMember(MemberCommonJoinRequestDTO dto) { .jobName(dto.jobName) .jobPart(dto.jobPart) .jobLocation(dto.jobLocation) + .jobPicture(dto.jobPicture) .eduName(dto.eduName) .eduMajor(dto.eduMajor) .eduLevel(dto.eduLevel) + .eduPicture(dto.eduPicture) .build(); return member; diff --git a/src/main/java/com/tikitaka/naechinso/domain/member/dto/MemberCommonResponseDTO.java b/src/main/java/com/tikitaka/naechinso/domain/member/dto/MemberCommonResponseDTO.java index 6940ad6..dfd6a22 100644 --- a/src/main/java/com/tikitaka/naechinso/domain/member/dto/MemberCommonResponseDTO.java +++ b/src/main/java/com/tikitaka/naechinso/domain/member/dto/MemberCommonResponseDTO.java @@ -3,8 +3,12 @@ import com.tikitaka.naechinso.domain.member.constant.Gender; import com.tikitaka.naechinso.domain.member.constant.Role; import com.tikitaka.naechinso.domain.member.entity.Member; +import io.swagger.annotations.ApiModelProperty; import lombok.*; +import javax.persistence.Column; +import javax.validation.constraints.NotBlank; + /** * 추천인 및 추천 받는 사람 공통 가입을 위한 Dto입니다 * @author gengminy 220924 @@ -26,6 +30,19 @@ public class MemberCommonResponseDTO { private int age; + private String jobName; + + private String jobPart; + + private String jobLocation; + + private String eduName; + + private String eduMajor; + + private String eduLevel; + + public static MemberCommonResponseDTO of(Member member) { MemberCommonResponseDTO res = MemberCommonResponseDTO.builder() .phone(member.getPhone()) @@ -33,6 +50,12 @@ public static MemberCommonResponseDTO of(Member member) { .name(member.getName()) .gender(member.getGender()) .age(member.getAge()) + .jobName(member.getJobName()) + .jobPart(member.getJobPart()) + .jobLocation(member.getJobLocation()) + .eduName(member.getEduName()) + .eduMajor(member.getEduMajor()) + .eduLevel(member.getEduLevel()) .build(); return res; diff --git a/src/main/java/com/tikitaka/naechinso/domain/member/dto/MemberEduUpdateRequestDTO.java b/src/main/java/com/tikitaka/naechinso/domain/member/dto/MemberEduUpdateRequestDTO.java index 21f510b..08ab20d 100644 --- a/src/main/java/com/tikitaka/naechinso/domain/member/dto/MemberEduUpdateRequestDTO.java +++ b/src/main/java/com/tikitaka/naechinso/domain/member/dto/MemberEduUpdateRequestDTO.java @@ -26,4 +26,8 @@ public class MemberEduUpdateRequestDTO { @ApiModelProperty(example = "대학교") @NotBlank(message = "최종학력을 입력해주세요") private String eduLevel; + + @ApiModelProperty(example = "인증 사진 링크") + @NotBlank(message = "인증 사진을 업로드 해주세요") + private String eduPicture; } diff --git a/src/main/java/com/tikitaka/naechinso/domain/member/dto/MemberJobUpdateRequestDTO.java b/src/main/java/com/tikitaka/naechinso/domain/member/dto/MemberJobUpdateRequestDTO.java index 9bd4ba0..7990630 100644 --- a/src/main/java/com/tikitaka/naechinso/domain/member/dto/MemberJobUpdateRequestDTO.java +++ b/src/main/java/com/tikitaka/naechinso/domain/member/dto/MemberJobUpdateRequestDTO.java @@ -26,4 +26,8 @@ public class MemberJobUpdateRequestDTO { @ApiModelProperty(example = "판교") @NotBlank(message = "직장 위치를 입력해주세요") private String jobLocation; + + @ApiModelProperty(example = "인증 사진 링크") + @NotBlank(message = "인증 사진을 업로드 해주세요") + private String jobPicture; } diff --git a/src/main/java/com/tikitaka/naechinso/domain/member/entity/Member.java b/src/main/java/com/tikitaka/naechinso/domain/member/entity/Member.java index 9527aad..e1c6016 100644 --- a/src/main/java/com/tikitaka/naechinso/domain/member/entity/Member.java +++ b/src/main/java/com/tikitaka/naechinso/domain/member/entity/Member.java @@ -79,6 +79,12 @@ public class Member extends BaseEntity { @Column(name = "mem_job_location") private String jobLocation; + @Column(name = "mem_job_picture") + private String jobPicture; + + @Column(name = "mem_job_accepted") + private String jobAccepted; + @Column(name = "mem_school") private String eduName; @@ -88,6 +94,21 @@ public class Member extends BaseEntity { @Column(name = "mem_edu_level") private String eduLevel; + @Column(name = "mem_edu_picture") + private String eduPicture; + + @Column(name = "mem_edu_accepted") + private String eduAccepted; + + @Column(name = "mem_join_accepted") + private String joinAccepted; + + //마지막으로 관리한 어드민 +// @OneToOne(fetch = FetchType.LAZY) +// @JoinColumn(name = "mem_admin_id") +// @JsonIgnore +// private Member adminId; + //가입했을 경우 정보 디테일 @OneToOne(mappedBy = "member") @JoinColumn(name = "mem_detail") @@ -113,11 +134,13 @@ public void updateJob(MemberJobUpdateRequestDTO requestDTO) { this.jobName = requestDTO.getJobName(); this.jobLocation = requestDTO.getJobLocation(); this.jobPart = requestDTO.getJobPart(); + this.jobPicture = requestDTO.getJobPicture(); } public void updateEdu(MemberEduUpdateRequestDTO requestDTO) { this.eduName = requestDTO.getEduName(); this.eduMajor = requestDTO.getEduMajor(); this.eduLevel = requestDTO.getEduLevel(); + this.eduPicture = requestDTO.getEduPicture(); } } diff --git a/src/main/java/com/tikitaka/naechinso/domain/recommend/RecommendController.java b/src/main/java/com/tikitaka/naechinso/domain/recommend/RecommendController.java index 4fd793e..f239415 100644 --- a/src/main/java/com/tikitaka/naechinso/domain/recommend/RecommendController.java +++ b/src/main/java/com/tikitaka/naechinso/domain/recommend/RecommendController.java @@ -39,9 +39,9 @@ public CommonApiResponse getRecommends( @PostMapping @ApiOperation(value = "추천서를 작성한 후, 추천인을 회원가입 시킨다. RegisterToken)") - public CommonApiResponse createRecommendNewSender( + public CommonApiResponse createRecommendAndJoinSender( HttpServletRequest request, - @Valid @RequestBody RecommendJoinRequestDTO dto) + @Valid @RequestBody RecommendAndJoinRequestDTO dto) { String phone = jwtTokenService.parsePhoneByRegisterToken(request); diff --git a/src/main/java/com/tikitaka/naechinso/domain/recommend/RecommendService.java b/src/main/java/com/tikitaka/naechinso/domain/recommend/RecommendService.java index dfdabfa..99b51f1 100644 --- a/src/main/java/com/tikitaka/naechinso/domain/recommend/RecommendService.java +++ b/src/main/java/com/tikitaka/naechinso/domain/recommend/RecommendService.java @@ -37,7 +37,7 @@ public RecommendListResponseDTO readRecommendList(Member authMember) { /** * 임시회원으로 등록하며 가입하지 않은 임의의 유저 추천사를 작성한다 * */ - public RecommendResponseDTO createRecommendJoin(String senderPhone, RecommendJoinRequestDTO dto) { + public RecommendResponseDTO createRecommendJoin(String senderPhone, RecommendAndJoinRequestDTO dto) { //멤버가 이미 있으면 종료 Optional checkSender = memberRepository.findByPhone(senderPhone); if (checkSender.isPresent()) { @@ -57,12 +57,12 @@ public RecommendResponseDTO createRecommendJoin(String senderPhone, RecommendJoi Recommend recommend = Recommend.builder() .sender(sender) .senderPhone(senderPhone) - .senderName(dto.getName()) - .senderAge(dto.getAge()) - .senderGender(dto.getGender()) - .senderJobName(dto.getJobName()) - .senderJobPart(dto.getJobPart()) - .senderJobLocation(dto.getJobLocation()) + .senderName(sender.getName()) + .senderAge(sender.getAge()) + .senderGender(sender.getGender()) + .senderJobName(sender.getJobName()) + .senderJobPart(sender.getJobPart()) + .senderJobLocation(sender.getJobLocation()) .receiver(receiver) .receiverPhone(dto.getReceiverPhone()) .receiverName(dto.getReceiverName()) @@ -172,7 +172,7 @@ public RecommendResponseDTO updateRecommendMemberAccept(String uuid, String send * 해당 유저 정보로 uuid 에 해당하는 추천사를 등록하며 * 직업 정보를 업데이트 한다 * */ - public RecommendResponseDTO updateRecommendMemberAccept(String uuid, String senderPhone, RecommendMemberAcceptWithUpdateJobRequestDTO dto) { + public RecommendResponseDTO updateRecommendMemberAccept(String uuid, String senderPhone, RecommendMemberAcceptAndUpdateRequestDTO dto) { Recommend recommend = findByUuidAndReceiverNotNull(uuid); @@ -190,23 +190,25 @@ public RecommendResponseDTO updateRecommendMemberAccept(String uuid, String send Member sender = memberRepository.findByPhone(senderPhone) .orElseThrow(() -> new BadRequestException(ErrorCode.USER_NOT_FOUND)); - MemberJobUpdateRequestDTO updateDTO1 = MemberJobUpdateRequestDTO.builder() - .jobLocation(dto.getJobLocation()) - .jobPart(dto.getJobPart()) - .jobName(dto.getJobName()) - .build(); - - sender.updateJob(updateDTO1); - - RecommendMemberAcceptRequestDTO updateDTO2 = RecommendMemberAcceptRequestDTO.builder() - .appeal(dto.getAppeal()) - .meet(dto.getMeet()) - .period(dto.getPeriod()) - .personality(dto.getPersonality()) - .build(); - - recommend.update(sender, updateDTO2); + //직업 정보가 있다면 업데이트 + if (dto.getJob() != null) { + MemberJobUpdateRequestDTO jobUpdateRequestDTO = MemberJobUpdateRequestDTO.builder() + .jobLocation(dto.getJob().getJobLocation()) + .jobPart(dto.getJob().getJobLocation()) + .jobName(dto.getJob().getJobName()) + .build(); + sender.updateJob(jobUpdateRequestDTO); + } + if (dto.getEdu() != null) { + RecommendMemberAcceptRequestDTO updateDTO2 = RecommendMemberAcceptRequestDTO.builder() + .appeal(dto.getAppeal()) + .meet(dto.getMeet()) + .period(dto.getPeriod()) + .personality(dto.getPersonality()) + .build(); + recommend.update(sender, updateDTO2); + } memberRepository.save(sender); recommendRepository.save(recommend); diff --git a/src/main/java/com/tikitaka/naechinso/domain/recommend/dto/RecommendJoinRequestDTO.java b/src/main/java/com/tikitaka/naechinso/domain/recommend/dto/RecommendAndJoinRequestDTO.java similarity index 74% rename from src/main/java/com/tikitaka/naechinso/domain/recommend/dto/RecommendJoinRequestDTO.java rename to src/main/java/com/tikitaka/naechinso/domain/recommend/dto/RecommendAndJoinRequestDTO.java index e12e67d..0250a7f 100644 --- a/src/main/java/com/tikitaka/naechinso/domain/recommend/dto/RecommendJoinRequestDTO.java +++ b/src/main/java/com/tikitaka/naechinso/domain/recommend/dto/RecommendAndJoinRequestDTO.java @@ -1,8 +1,9 @@ package com.tikitaka.naechinso.domain.recommend.dto; import com.tikitaka.naechinso.domain.member.constant.Gender; +import com.tikitaka.naechinso.domain.member.dto.MemberEduUpdateRequestDTO; +import com.tikitaka.naechinso.domain.member.dto.MemberJobUpdateRequestDTO; import com.tikitaka.naechinso.domain.member.entity.Member; -import com.tikitaka.naechinso.domain.recommend.entity.Recommend; import com.tikitaka.naechinso.global.annotation.Enum; import io.swagger.annotations.ApiModelProperty; import lombok.*; @@ -17,7 +18,7 @@ @Getter @Builder @ToString -public class RecommendJoinRequestDTO { +public class RecommendAndJoinRequestDTO { @ApiModelProperty(example = "닉") @NotBlank(message = "이름을 입력해주세요") private String name; @@ -49,17 +50,11 @@ public class RecommendJoinRequestDTO { @NotNull(message = "마케팅 동의 여부가 필요합니다") private boolean acceptsMarketing; - @ApiModelProperty(example = "카카오") - @NotBlank(message = "직장명을 입력해주세요") - private String jobName; + private MemberEduUpdateRequestDTO edu; + + private MemberJobUpdateRequestDTO job; - @ApiModelProperty(example = "개발자") - @NotBlank(message = "직장 부서를 입력해주세요") - private String jobPart; - @ApiModelProperty(example = "판교") - @NotBlank(message = "직장 위치를 입력해주세요") - private String jobLocation; @@ -98,7 +93,22 @@ public class RecommendJoinRequestDTO { private String period; public Member toSender(String phone){ - return Member.builder() + Member.MemberBuilder builder = Member.builder(); + if (this.job != null) { + builder.jobName(this.job.getJobName()) + .jobPart(this.job.getJobPart()) + .jobLocation(this.job.getJobLocation()) + .jobPicture(this.job.getJobPicture()); + } + + if (this.edu != null) { + builder.eduName(this.edu.getEduName()) + .eduMajor(this.edu.getEduMajor()) + .eduLevel(this.edu.getEduMajor()) + .eduPicture(this.edu.getEduPicture()); + } + + return builder .phone(phone) .name(this.name) .gender(this.gender) @@ -108,13 +118,25 @@ public Member toSender(String phone){ .acceptsReligion(this.acceptsReligion) .acceptsLocation(this.acceptsLocation) .acceptsMarketing(this.acceptsMarketing) - .jobName(this.jobName) - .jobPart(this.jobPart) - .jobLocation(this.jobLocation) .build(); } public Member toReceiver(String phone){ + Member.MemberBuilder builder = Member.builder(); + if (job != null) { + builder.jobName(this.job.getJobName()) + .jobPart(this.job.getJobPart()) + .jobLocation(this.job.getJobLocation()) + .jobPicture(this.job.getJobPicture()); + } + + if (edu != null) { + builder.eduName(this.edu.getEduName()) + .eduMajor(this.edu.getEduMajor()) + .eduLevel(this.edu.getEduMajor()) + .eduPicture(this.edu.getEduPicture()); + } + return Member.builder() .phone(phone) .name(this.name) @@ -125,9 +147,6 @@ public Member toReceiver(String phone){ .acceptsReligion(this.acceptsReligion) .acceptsLocation(this.acceptsLocation) .acceptsMarketing(this.acceptsMarketing) - .jobName(this.jobName) - .jobPart(this.jobPart) - .jobLocation(this.jobLocation) .build(); } } diff --git a/src/main/java/com/tikitaka/naechinso/domain/recommend/dto/RecommendMemberAcceptWithUpdateJobRequestDTO.java b/src/main/java/com/tikitaka/naechinso/domain/recommend/dto/RecommendMemberAcceptAndUpdateRequestDTO.java similarity index 52% rename from src/main/java/com/tikitaka/naechinso/domain/recommend/dto/RecommendMemberAcceptWithUpdateJobRequestDTO.java rename to src/main/java/com/tikitaka/naechinso/domain/recommend/dto/RecommendMemberAcceptAndUpdateRequestDTO.java index 46e5f08..7097f9c 100644 --- a/src/main/java/com/tikitaka/naechinso/domain/recommend/dto/RecommendMemberAcceptWithUpdateJobRequestDTO.java +++ b/src/main/java/com/tikitaka/naechinso/domain/recommend/dto/RecommendMemberAcceptAndUpdateRequestDTO.java @@ -1,8 +1,7 @@ package com.tikitaka.naechinso.domain.recommend.dto; -import com.tikitaka.naechinso.domain.member.constant.Gender; -import com.tikitaka.naechinso.domain.member.entity.Member; -import com.tikitaka.naechinso.global.annotation.Enum; +import com.tikitaka.naechinso.domain.member.dto.MemberEduUpdateRequestDTO; +import com.tikitaka.naechinso.domain.member.dto.MemberJobUpdateRequestDTO; import io.swagger.annotations.ApiModelProperty; import lombok.*; @@ -13,18 +12,25 @@ @Getter @Builder @ToString -public class RecommendMemberAcceptWithUpdateJobRequestDTO { - @ApiModelProperty(example = "카카오") - @NotBlank(message = "직장명을 입력해주세요") - private String jobName; - - @ApiModelProperty(example = "개발자") - @NotBlank(message = "직장 부서를 입력해주세요") - private String jobPart; - - @ApiModelProperty(example = "판교") - @NotBlank(message = "직장 위치를 입력해주세요") - private String jobLocation; +public class RecommendMemberAcceptAndUpdateRequestDTO { + + + @ApiModelProperty + private MemberEduUpdateRequestDTO edu; + + @ApiModelProperty + private MemberJobUpdateRequestDTO job; + +// @NotBlank(message = "직장명을 입력해주세요") +// private String jobName; +// +// @ApiModelProperty(example = "개발자") +// @NotBlank(message = "직장 부서를 입력해주세요") +// private String jobPart; +// +// @ApiModelProperty(example = "판교") +// @NotBlank(message = "직장 위치를 입력해주세요") +// private String jobLocation; @ApiModelProperty(example = "CMC 에서") @NotBlank(message = "만나게 된 계기를 입력해주세요") From 8f38dbaa57a609f8b361af648b255f128023af67 Mon Sep 17 00:00:00 2001 From: gengminy Date: Fri, 7 Oct 2022 02:48:29 +0900 Subject: [PATCH 17/72] =?UTF-8?q?:hammer:=20fix(user):=20=EC=9C=A0?= =?UTF-8?q?=EC=A0=80=20=EA=B0=80=EC=9E=85=20url=20=EC=88=98=EC=A0=95=20#20?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../domain/member/MemberController.java | 57 ++++++++----------- .../domain/member/MemberService.java | 37 +++++++++--- .../dto/MemberCommonJoinRequestDTO.java | 50 +--------------- .../dto/MemberCommonJoinResponseDTO.java | 52 +++++++++++++++++ .../dto/MemberDetailJoinRequestDTO.java | 29 ++++++---- .../dto/MemberUpdateCommonRequestDTO.java | 30 ++++++++++ .../domain/member/entity/Member.java | 8 +++ .../domain/recommend/RecommendController.java | 2 +- .../domain/recommend/RecommendRepository.java | 2 + .../domain/recommend/RecommendService.java | 9 +++ .../recommend/dto/RecommendReceiverDTO.java | 29 ++++++++++ .../sms/SmsCertificationServiceImpl.java | 21 +++++-- .../SmsCertificationSuccessResponseDTO.java | 6 +- 13 files changed, 225 insertions(+), 107 deletions(-) create mode 100644 src/main/java/com/tikitaka/naechinso/domain/member/dto/MemberCommonJoinResponseDTO.java create mode 100644 src/main/java/com/tikitaka/naechinso/domain/member/dto/MemberUpdateCommonRequestDTO.java create mode 100644 src/main/java/com/tikitaka/naechinso/domain/recommend/dto/RecommendReceiverDTO.java diff --git a/src/main/java/com/tikitaka/naechinso/domain/member/MemberController.java b/src/main/java/com/tikitaka/naechinso/domain/member/MemberController.java index ed7561b..10c6365 100644 --- a/src/main/java/com/tikitaka/naechinso/domain/member/MemberController.java +++ b/src/main/java/com/tikitaka/naechinso/domain/member/MemberController.java @@ -29,6 +29,7 @@ public class MemberController { private final RecommendService recommendService; private final JwtTokenProvider jwtTokenService; + @GetMapping @ApiOperation(value = "유저 자신의 모든 정보를 가져온다 (AccessToken)") public CommonApiResponse getMyInformation( @@ -38,20 +39,6 @@ public CommonApiResponse getMyInformation( return CommonApiResponse.of(MemberCommonResponseDTO.of(member)); } -// @PostMapping("/join") -// @ApiOperation(value = "공통 유저를 기본 정보로 회원가입 시킨다 (registerToken 필요)") -// public CommonApiResponse joinCommonMember( -// HttpServletRequest request, -// @Valid @RequestBody MemberCommonJoinRequestDTO dto) -// { -// String registerToken = request.getHeader("Authorization"); -// if (StringUtils.isBlank(registerToken) || !jwtTokenService.validateToken(registerToken)) { -// throw new UnauthorizedException(ErrorCode.NO_TOKEN); -// } -// -// final MemberCommonResponseDTO res = memberService.createCommonMember(dto); -// return CommonApiResponse.of(res); -// } @GetMapping("/detail") @ApiOperation(value = "회원가입 세부 정보를 가져온다 (AccessToken 필요)") @@ -62,6 +49,26 @@ public CommonApiResponse getMemberDetail( return CommonApiResponse.of(res); } + + @PostMapping("/join") + @ApiOperation(value = "유저를 공통 정보로 가입시킨다 (RegisterToken)") + public CommonApiResponse joinCommonMember( + HttpServletRequest request, + @Valid @RequestBody MemberCommonJoinRequestDTO dto + ) { + String phone = jwtTokenService.parsePhoneByRegisterToken(request); + return CommonApiResponse.of(memberService.joinCommonMember(phone, dto)); + } + + @PatchMapping("/common") + @ApiOperation(value = "유저를 공통 정보를 수정한다 (AccessToken)") + public CommonApiResponse updateCommonMember( + @Valid @RequestBody MemberUpdateCommonRequestDTO dto, + @ApiIgnore @AuthMember Member member + ) { + return CommonApiResponse.of(memberService.updateCommonMember(member, dto)); + } + @PatchMapping("/job") @ApiOperation(value = "직업 정보를 업데이트 한다 (AccessToken)") public CommonApiResponse setMemberJob( @@ -81,20 +88,6 @@ public CommonApiResponse setMemberJob( } - @PostMapping("/join") - @ApiOperation(value = "유저를 공통 정보로 가입시킨다 (RegisterToken)") - public CommonApiResponse join( - HttpServletRequest request, - @Valid @RequestBody MemberDetailJoinRequestDTO dto - ) { - return null; -// //로그인 상태가 아닌 경우 401 -// if (member == null) { -// throw new UnauthorizedException(ErrorCode.UNAUTHORIZED_USER); -// } -// final MemberDetailResponseDTO res = memberService.createDetail(member, dto); -// return CommonApiResponse.of(res); - } @PostMapping("/join/detail") @@ -124,7 +117,7 @@ public CommonApiResponse createRecommend( @ApiIgnore @AuthMember Member member ) { //로그인 상태가 아닌 경우 401 - memberService.validateLoggedIn(member); + memberService.validateToken(member); return CommonApiResponse.of(null); } @@ -133,7 +126,7 @@ public CommonApiResponse createRecommend( * @// TODO: 2022/10/05 직업 정보가 없는 사람이 가입할 때 직업 정보 입력해야 하는 처리 필요 * */ @PatchMapping("/recommend/{uuid}/accept") - @ApiOperation(value = "요청받은 uuid 추천사에 자신을 추천인으로 등록한다 (AccessToken)") + @ApiOperation(value = "요청받은 uuid 추천사에 자신을 추천인으로 등록한다 (삭제예정)") public CommonApiResponse updateRecommendByUuid( @PathVariable("uuid") String uuid, @Valid @RequestBody RecommendMemberAcceptAndUpdateRequestDTO dto, @@ -151,7 +144,7 @@ public CommonApiResponse updateRecommendByUuid( * 직업 인증으로 추천인을 가입시킨다 * */ @PatchMapping("/recommend/{uuid}/accept/job") - @ApiOperation(value = "요청받은 uuid 추천사에 자신을 추천인으로 등록하며 직업 정보를 업데이트 한다 (AccessToken)") + @ApiOperation(value = "요청받은 uuid 추천사에 자신을 추천인으로 등록하며 직업 정보를 업데이트 한다 (삭제예정)") public CommonApiResponse updateRecommendByUuidAndJob( @PathVariable("uuid") String uuid, @Valid @RequestBody RecommendMemberAcceptAndUpdateRequestDTO dto, @@ -168,7 +161,7 @@ public CommonApiResponse updateRecommendByUuidAndJob( * 학교 인증으로 추천인을 가입시킨다 * */ @PatchMapping("/recommend/{uuid}/accept/edu") - @ApiOperation(value = "요청받은 uuid 추천사에 자신을 추천인으로 등록하며 학교 정보를 업데이트 한다 (AccessToken)") + @ApiOperation(value = "요청받은 uuid 추천사에 자신을 추천인으로 등록하며 학교 정보를 업데이트 한다 (삭제예정)") public CommonApiResponse updateRecommendByUuidAndEdu( @PathVariable("uuid") String uuid, @Valid @RequestBody RecommendMemberAcceptAndUpdateRequestDTO dto, diff --git a/src/main/java/com/tikitaka/naechinso/domain/member/MemberService.java b/src/main/java/com/tikitaka/naechinso/domain/member/MemberService.java index a3042c4..bc61b04 100644 --- a/src/main/java/com/tikitaka/naechinso/domain/member/MemberService.java +++ b/src/main/java/com/tikitaka/naechinso/domain/member/MemberService.java @@ -38,19 +38,38 @@ public List findAll() { } - public MemberCommonResponseDTO createCommonMember(MemberCommonJoinRequestDTO dto) { - + public MemberCommonJoinResponseDTO joinCommonMember(String phone, MemberCommonJoinRequestDTO dto) { //이미 존재하는 유저일 경우 400 - Optional checkMember = memberRepository.findByPhone(dto.getPhone()); - if(!checkMember.isEmpty()) { + Optional checkMember = memberRepository.findByPhone(phone); + if(checkMember.isPresent()) { throw new BadRequestException(ErrorCode.USER_ALREADY_EXIST); } - Member member = MemberCommonJoinRequestDTO.toCommonMember(dto); + Member member = MemberCommonJoinRequestDTO.toCommonMember(phone, dto); memberRepository.save(member); - MemberCommonResponseDTO res = MemberCommonResponseDTO.of(member); - return res; + TokenResponseDTO tokenResponseDTO + = jwtTokenProvider.generateToken(new JwtDTO(phone, "ROLE_USER")); + + return MemberCommonJoinResponseDTO.of(member, tokenResponseDTO); + } + + public MemberCommonJoinResponseDTO updateCommonMember(Member authMember, MemberUpdateCommonRequestDTO dto) { + //없는 유저면 404 + final String phone = authMember.getPhone(); + Optional checkMember = memberRepository.findByPhone(phone); + if(checkMember.isEmpty()) { + throw new NotFoundException(ErrorCode.USER_NOT_FOUND); + } + + Member member = checkMember.get(); + member.updateCommon(dto); + memberRepository.save(member); + + TokenResponseDTO tokenResponseDTO + = jwtTokenProvider.generateToken(new JwtDTO(phone, "ROLE_USER")); + + return MemberCommonJoinResponseDTO.of(member); } public TokenResponseDTO login(String phone) { @@ -117,14 +136,14 @@ public MemberCommonResponseDTO updateEdu(Member authMember, MemberEduUpdateReque } - public void validateLoggedIn(Member authMember) { + public void validateToken(Member authMember) { if (authMember == null) { throw new UnauthorizedException(ErrorCode.UNAUTHORIZED_USER); } } public void validateFormalMember(Member authMember) { - validateLoggedIn(authMember); + validateToken(authMember); if (authMember.getDetail() == null) { throw new UnauthorizedException(ErrorCode.FORBIDDEN_USER); } diff --git a/src/main/java/com/tikitaka/naechinso/domain/member/dto/MemberCommonJoinRequestDTO.java b/src/main/java/com/tikitaka/naechinso/domain/member/dto/MemberCommonJoinRequestDTO.java index 6859cf9..d40136c 100644 --- a/src/main/java/com/tikitaka/naechinso/domain/member/dto/MemberCommonJoinRequestDTO.java +++ b/src/main/java/com/tikitaka/naechinso/domain/member/dto/MemberCommonJoinRequestDTO.java @@ -9,7 +9,7 @@ import javax.validation.constraints.*; /** - * 추천인 및 추천 받는 사람 공통 가입을 위한 Dto입니다 + * 임시회원의 가입을 위한 Dto입니다 * @author gengminy 220924 * */ @AllArgsConstructor @@ -18,11 +18,6 @@ @Builder @ToString public class MemberCommonJoinRequestDTO { - @ApiModelProperty(example = "01010001000") - @NotBlank(message = "전화번호를 입력해주세요") - @Pattern(regexp = "[0-9]{10,11}", message = "하이픈 없는 10~11자리 숫자를 입력해주세요") - private String phone; - @ApiModelProperty(example = "닉") @NotBlank(message = "이름을 입력해주세요") private String name; @@ -54,40 +49,9 @@ public class MemberCommonJoinRequestDTO { @NotNull(message = "마케팅 동의 여부가 필요합니다") private boolean acceptsMarketing; - @ApiModelProperty(example = "카카오") - @NotBlank(message = "직장명을 입력해주세요") - private String jobName; - - @ApiModelProperty(example = "개발자") - @NotBlank(message = "직장 부서를 입력해주세요") - private String jobPart; - - @ApiModelProperty(example = "판교") - @NotBlank(message = "직장 위치를 입력해주세요") - private String jobLocation; - - @ApiModelProperty(example = "인증 사진 링크") - @NotBlank(message = "인증 사진을 업로드 해주세요") - private String jobPicture; - @ApiModelProperty(example = "서울") - @NotBlank(message = "학교명을 입력해주세요") - private String eduName; - - @ApiModelProperty(example = "컴퓨터공학과") - @NotBlank(message = "전공을 입력해주세요") - private String eduMajor; - - @ApiModelProperty(example = "대학교") - @NotBlank(message = "최종학력을 입력해주세요") - private String eduLevel; - - @ApiModelProperty(example = "인증 사진 링크") - @NotBlank(message = "인증 사진을 업로드 해주세요") - private String eduPicture; - - public static Member toCommonMember(MemberCommonJoinRequestDTO dto) { + public static Member toCommonMember(String phone, MemberCommonJoinRequestDTO dto) { Member member = Member.builder() - .phone(dto.phone) + .phone(phone) .name(dto.name) .gender(dto.gender) .age(dto.age) @@ -96,14 +60,6 @@ public static Member toCommonMember(MemberCommonJoinRequestDTO dto) { .acceptsReligion(dto.acceptsReligion) .acceptsLocation(dto.acceptsLocation) .acceptsMarketing(dto.acceptsMarketing) - .jobName(dto.jobName) - .jobPart(dto.jobPart) - .jobLocation(dto.jobLocation) - .jobPicture(dto.jobPicture) - .eduName(dto.eduName) - .eduMajor(dto.eduMajor) - .eduLevel(dto.eduLevel) - .eduPicture(dto.eduPicture) .build(); return member; diff --git a/src/main/java/com/tikitaka/naechinso/domain/member/dto/MemberCommonJoinResponseDTO.java b/src/main/java/com/tikitaka/naechinso/domain/member/dto/MemberCommonJoinResponseDTO.java new file mode 100644 index 0000000..a759c8e --- /dev/null +++ b/src/main/java/com/tikitaka/naechinso/domain/member/dto/MemberCommonJoinResponseDTO.java @@ -0,0 +1,52 @@ +package com.tikitaka.naechinso.domain.member.dto; + +import com.fasterxml.jackson.annotation.JsonInclude; +import com.tikitaka.naechinso.domain.member.constant.Gender; +import com.tikitaka.naechinso.domain.member.entity.Member; +import com.tikitaka.naechinso.global.annotation.Enum; +import com.tikitaka.naechinso.global.common.response.TokenResponseDTO; +import io.swagger.annotations.ApiModelProperty; +import lombok.*; + +import javax.validation.constraints.*; + +/** + * 임시회원의 가입 정보를 리턴하는 DTO 입니다 + * @author gengminy 221006 + * */ +@AllArgsConstructor +@NoArgsConstructor +@Getter +@Builder +@ToString +@JsonInclude(JsonInclude.Include.NON_NULL) //NULL 필드 가림 +public class MemberCommonJoinResponseDTO { + + private String phone; + private String name; + private Gender gender; + private int age; + + private String accessToken; + private String refreshToken; + + public static MemberCommonJoinResponseDTO of(Member member, TokenResponseDTO tokenDTO) { + return MemberCommonJoinResponseDTO.builder() + .phone(member.getPhone()) + .name(member.getName()) + .gender(member.getGender()) + .age(member.getAge()) + .accessToken(tokenDTO.getAccessToken()) + .refreshToken(tokenDTO.getRefreshToken()) + .build(); + } + + public static MemberCommonJoinResponseDTO of(Member member) { + return MemberCommonJoinResponseDTO.builder() + .phone(member.getPhone()) + .name(member.getName()) + .gender(member.getGender()) + .age(member.getAge()) + .build(); + } +} diff --git a/src/main/java/com/tikitaka/naechinso/domain/member/dto/MemberDetailJoinRequestDTO.java b/src/main/java/com/tikitaka/naechinso/domain/member/dto/MemberDetailJoinRequestDTO.java index 5708afb..20b4211 100644 --- a/src/main/java/com/tikitaka/naechinso/domain/member/dto/MemberDetailJoinRequestDTO.java +++ b/src/main/java/com/tikitaka/naechinso/domain/member/dto/MemberDetailJoinRequestDTO.java @@ -1,5 +1,7 @@ package com.tikitaka.naechinso.domain.member.dto; +import com.tikitaka.naechinso.domain.member.constant.Gender; +import com.tikitaka.naechinso.global.annotation.Enum; import io.swagger.annotations.ApiModelProperty; import lombok.*; import org.hibernate.validator.constraints.Length; @@ -16,8 +18,20 @@ @Builder @ToString public class MemberDetailJoinRequestDTO { - //추천인 정보 - // + + @ApiModelProperty(example = "닉") + @NotBlank(message = "이름을 입력해주세요") + private String name; + + @ApiModelProperty(example = "M") + @Enum(enumClass = Gender.class, message = "성별 입력이 올바르지 않습니다. M 또는 W가 필요합니다") + private Gender gender; + + @ApiModelProperty(example = "25") + @Min(value = 25, message = "25-33세까지만 가입 가능합니다") + @Max(value = 33, message = "25-33세까지만 가입 가능합니다") + private int age; + @ApiModelProperty(example = "180") @Positive(message = "키는 양수여야 합니다") private int height; @@ -36,7 +50,7 @@ public class MemberDetailJoinRequestDTO { private String smoke; @ApiModelProperty(example = "ESTJ") - @Length(max = 4, message = "올바를 MBTI 정보를 입력하세요") + @Length(max = 4, message = "올바른 MBTI 정보를 입력하세요") private String mbti = ""; @NotBlank(message = "성격 정보를 입력해야 합니다") @@ -54,13 +68,4 @@ public class MemberDetailJoinRequestDTO { @NotBlank(message = "사진을 업로드해야 합니다") private String picture; - @ApiModelProperty(example = "서울") - private String school; - - @ApiModelProperty(example = "컴퓨터공학과") - private String major; - - @ApiModelProperty(example = "대학교") - private String eduLevel; - } diff --git a/src/main/java/com/tikitaka/naechinso/domain/member/dto/MemberUpdateCommonRequestDTO.java b/src/main/java/com/tikitaka/naechinso/domain/member/dto/MemberUpdateCommonRequestDTO.java new file mode 100644 index 0000000..40fef9d --- /dev/null +++ b/src/main/java/com/tikitaka/naechinso/domain/member/dto/MemberUpdateCommonRequestDTO.java @@ -0,0 +1,30 @@ +package com.tikitaka.naechinso.domain.member.dto; + +import com.tikitaka.naechinso.domain.member.constant.Gender; +import com.tikitaka.naechinso.global.annotation.Enum; +import io.swagger.annotations.ApiModelProperty; +import lombok.*; + +import javax.validation.constraints.Max; +import javax.validation.constraints.Min; +import javax.validation.constraints.NotBlank; + +@AllArgsConstructor +@NoArgsConstructor +@Getter +@Builder +@ToString +public class MemberUpdateCommonRequestDTO { + @ApiModelProperty(example = "닉") + @NotBlank(message = "이름을 입력해주세요") + private String name; + + @ApiModelProperty(example = "M") + @Enum(enumClass = Gender.class, message = "성별 입력이 올바르지 않습니다. M 또는 W가 필요합니다") + private Gender gender; + + @ApiModelProperty(example = "25") + @Min(value = 25, message = "25-33세까지만 가입 가능합니다") + @Max(value = 33, message = "25-33세까지만 가입 가능합니다") + private int age; +} diff --git a/src/main/java/com/tikitaka/naechinso/domain/member/entity/Member.java b/src/main/java/com/tikitaka/naechinso/domain/member/entity/Member.java index e1c6016..68ceb7d 100644 --- a/src/main/java/com/tikitaka/naechinso/domain/member/entity/Member.java +++ b/src/main/java/com/tikitaka/naechinso/domain/member/entity/Member.java @@ -3,6 +3,7 @@ import com.fasterxml.jackson.annotation.JsonIgnore; import com.tikitaka.naechinso.domain.member.constant.Gender; import com.tikitaka.naechinso.domain.member.constant.Role; +import com.tikitaka.naechinso.domain.member.dto.MemberUpdateCommonRequestDTO; import com.tikitaka.naechinso.domain.member.dto.MemberEduUpdateRequestDTO; import com.tikitaka.naechinso.domain.member.dto.MemberJobUpdateRequestDTO; import com.tikitaka.naechinso.domain.recommend.entity.Recommend; @@ -143,4 +144,11 @@ public void updateEdu(MemberEduUpdateRequestDTO requestDTO) { this.eduLevel = requestDTO.getEduLevel(); this.eduPicture = requestDTO.getEduPicture(); } + + public void updateCommon(MemberUpdateCommonRequestDTO dto) { + this.name = dto.getName(); + this.gender = dto.getGender(); + this.age = dto.getAge(); + } + } diff --git a/src/main/java/com/tikitaka/naechinso/domain/recommend/RecommendController.java b/src/main/java/com/tikitaka/naechinso/domain/recommend/RecommendController.java index f239415..a22cf91 100644 --- a/src/main/java/com/tikitaka/naechinso/domain/recommend/RecommendController.java +++ b/src/main/java/com/tikitaka/naechinso/domain/recommend/RecommendController.java @@ -38,7 +38,7 @@ public CommonApiResponse getRecommends( } @PostMapping - @ApiOperation(value = "추천서를 작성한 후, 추천인을 회원가입 시킨다. RegisterToken)") + @ApiOperation(value = "추천서를 작성한 후, 추천인을 회원가입 시킨다. (삭제예정 -> 다른 유저의 추천서를 작성한다)") public CommonApiResponse createRecommendAndJoinSender( HttpServletRequest request, @Valid @RequestBody RecommendAndJoinRequestDTO dto) diff --git a/src/main/java/com/tikitaka/naechinso/domain/recommend/RecommendRepository.java b/src/main/java/com/tikitaka/naechinso/domain/recommend/RecommendRepository.java index 0d267d0..baba456 100644 --- a/src/main/java/com/tikitaka/naechinso/domain/recommend/RecommendRepository.java +++ b/src/main/java/com/tikitaka/naechinso/domain/recommend/RecommendRepository.java @@ -14,6 +14,8 @@ public interface RecommendRepository extends JpaRepository { List findAllByReceiver_Id(Long id); List findAllByReceiverPhone(String phone); + + List findAllByReceiverPhoneAndSenderNotNull(String phone); List findAllBySender_Id(Long id); List findAllBySenderPhone(String phone); diff --git a/src/main/java/com/tikitaka/naechinso/domain/recommend/RecommendService.java b/src/main/java/com/tikitaka/naechinso/domain/recommend/RecommendService.java index 99b51f1..21900a7 100644 --- a/src/main/java/com/tikitaka/naechinso/domain/recommend/RecommendService.java +++ b/src/main/java/com/tikitaka/naechinso/domain/recommend/RecommendService.java @@ -16,6 +16,7 @@ import java.util.ArrayList; import java.util.List; import java.util.Optional; +import java.util.stream.Collectors; @Service @RequiredArgsConstructor @@ -34,6 +35,14 @@ public RecommendListResponseDTO readRecommendList(Member authMember) { return RecommendListResponseDTO.of(member); } + /** + * 휴대폰 번호로 받은 추천사 기본 정보를 가져온다 + * */ + public List findAllRecommendReceivedListBasicByPhone(String phone) { + return recommendRepository.findAllByReceiverPhoneAndSenderNotNull(phone) + .stream().map(RecommendReceiverDTO::of).collect(Collectors.toList()); + } + /** * 임시회원으로 등록하며 가입하지 않은 임의의 유저 추천사를 작성한다 * */ diff --git a/src/main/java/com/tikitaka/naechinso/domain/recommend/dto/RecommendReceiverDTO.java b/src/main/java/com/tikitaka/naechinso/domain/recommend/dto/RecommendReceiverDTO.java new file mode 100644 index 0000000..b33473a --- /dev/null +++ b/src/main/java/com/tikitaka/naechinso/domain/recommend/dto/RecommendReceiverDTO.java @@ -0,0 +1,29 @@ +package com.tikitaka.naechinso.domain.recommend.dto; + +import com.tikitaka.naechinso.domain.member.constant.Gender; +import com.tikitaka.naechinso.domain.recommend.entity.Recommend; +import lombok.*; + +/** + * 유저 초기화면에서 반환할 받은 추천사 정보 DTO + * */ +@AllArgsConstructor +@NoArgsConstructor +@Getter +@Builder +@ToString +public class RecommendReceiverDTO { + private String name; + + private Gender gender; + + private int age; + + public static RecommendReceiverDTO of(Recommend recommend) { + return RecommendReceiverDTO.builder() + .name(recommend.getReceiverName()) + .gender(recommend.getReceiverGender()) + .name(recommend.getReceiverName()) + .build(); + } +} diff --git a/src/main/java/com/tikitaka/naechinso/domain/sms/SmsCertificationServiceImpl.java b/src/main/java/com/tikitaka/naechinso/domain/sms/SmsCertificationServiceImpl.java index c405945..4632df5 100644 --- a/src/main/java/com/tikitaka/naechinso/domain/sms/SmsCertificationServiceImpl.java +++ b/src/main/java/com/tikitaka/naechinso/domain/sms/SmsCertificationServiceImpl.java @@ -3,6 +3,7 @@ import com.tikitaka.naechinso.domain.member.MemberRepository; import com.tikitaka.naechinso.domain.member.entity.Member; import com.tikitaka.naechinso.domain.recommend.RecommendService; +import com.tikitaka.naechinso.domain.recommend.dto.RecommendReceiverDTO; import com.tikitaka.naechinso.domain.recommend.dto.RecommendResponseDTO; import com.tikitaka.naechinso.domain.sms.dto.SmsCertificationSuccessResponseDTO; import com.tikitaka.naechinso.global.common.response.TokenResponseDTO; @@ -104,8 +105,9 @@ public SmsCertificationSuccessResponseDTO verifyCode(SmsCertificationRequestDTO //redis 에서 번호 제거 redisService.deleteValues(key); - //추천 받은 정보가 있는지 - Boolean recommendReceived = recommendService.existsByReceiverPhoneAndSenderNotNull(phoneNumber); + //유효한 추천인이 있는 추천사 리스트 + List recommendReceivedList + = recommendService.findAllRecommendReceivedListBasicByPhone(phoneNumber); //가입 안된 회원일 경우 registerToken 리턴 Optional checkMember = memberRepository.findByPhone(phoneNumber); @@ -114,20 +116,29 @@ public SmsCertificationSuccessResponseDTO verifyCode(SmsCertificationRequestDTO return SmsCertificationSuccessResponseDTO.builder() .registerToken(registerToken) - .recommendReceived(recommendReceived) + .recommendReceived(recommendReceivedList) .build(); } + //이미 가입한 회원이면 //인증한 휴대폰 번호로 로그인 후 토큰 생성 + final Member authMember = checkMember.get(); TokenResponseDTO tokenResponseDTO - = jwtTokenProvider.generateToken(new JwtDTO(phoneNumber, checkMember.get().getRole().getDetail())); + = jwtTokenProvider.generateToken(new JwtDTO(phoneNumber, authMember.getRole().getDetail())); + + //가입 여부 (detail == null) 확인 후 받은 추천서 꺼내옴 + final Boolean hasDetail = authMember.getDetail() != null; + //유저 밴 여부 + final Boolean isBanned = false; //액세스 + 리프레시 토큰 반환 return SmsCertificationSuccessResponseDTO.builder() .accessToken(tokenResponseDTO.getAccessToken()) .refreshToken(tokenResponseDTO.getRefreshToken()) - .recommendReceived(recommendReceived) + .recommendReceived(recommendReceivedList) + .isActive(hasDetail) + .isBanned(false) .build(); } catch (Exception e) { e.printStackTrace(); diff --git a/src/main/java/com/tikitaka/naechinso/domain/sms/dto/SmsCertificationSuccessResponseDTO.java b/src/main/java/com/tikitaka/naechinso/domain/sms/dto/SmsCertificationSuccessResponseDTO.java index 6df139e..691cdb6 100644 --- a/src/main/java/com/tikitaka/naechinso/domain/sms/dto/SmsCertificationSuccessResponseDTO.java +++ b/src/main/java/com/tikitaka/naechinso/domain/sms/dto/SmsCertificationSuccessResponseDTO.java @@ -1,6 +1,7 @@ package com.tikitaka.naechinso.domain.sms.dto; import com.fasterxml.jackson.annotation.JsonInclude; +import com.tikitaka.naechinso.domain.recommend.dto.RecommendReceiverDTO; import com.tikitaka.naechinso.domain.recommend.dto.RecommendResponseDTO; import lombok.*; @@ -19,5 +20,8 @@ public class SmsCertificationSuccessResponseDTO { private String registerToken; //추천 받았는지 여부, true 면 유효한 유저 - private Boolean recommendReceived = false; + private List recommendReceived = new ArrayList<>(); + //가입 완료했는지 여부, detail 정보가 있으면 true + private Boolean isActive = false; + private Boolean isBanned = false; } From 1f558b2346f2ac08d77c5eec214ebe6ef4a2947d Mon Sep 17 00:00:00 2001 From: gengminy Date: Fri, 7 Oct 2022 13:36:24 +0900 Subject: [PATCH 18/72] =?UTF-8?q?:hammer:=20refactor(url):=20=EB=A9=A4?= =?UTF-8?q?=EB=B2=84=EC=99=80=20=EC=B6=94=EC=B2=9C=20url=20=EA=B8=B0?= =?UTF-8?q?=EB=8A=A5=EB=B3=84=20=EB=B6=84=EB=A6=AC=20#32?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../domain/member/MemberController.java | 65 ------- .../domain/member/MemberRepository.java | 1 + .../domain/member/MemberService.java | 36 ++-- .../domain/recommend/RecommendController.java | 43 ++-- .../domain/recommend/RecommendRepository.java | 2 + .../domain/recommend/RecommendService.java | 184 ++++++------------ .../dto/RecommendAcceptRequestDTO.java | 33 ++++ .../RecommendAcceptWithJoinRequestDTO.java | 106 ---------- .../dto/RecommendAndJoinRequestDTO.java | 152 --------------- .../dto/RecommendBySenderRequestDTO.java | 146 ++++++++++++++ .../recommend/dto/RecommendRequestDTO.java | 64 ------ .../domain/recommend/entity/Recommend.java | 19 +- .../sms/SmsCertificationController.java | 3 + .../config/security/SecurityConfig.java | 5 +- .../naechinso/global/error/ErrorCode.java | 5 +- 15 files changed, 292 insertions(+), 572 deletions(-) create mode 100644 src/main/java/com/tikitaka/naechinso/domain/recommend/dto/RecommendAcceptRequestDTO.java delete mode 100644 src/main/java/com/tikitaka/naechinso/domain/recommend/dto/RecommendAcceptWithJoinRequestDTO.java delete mode 100644 src/main/java/com/tikitaka/naechinso/domain/recommend/dto/RecommendAndJoinRequestDTO.java create mode 100644 src/main/java/com/tikitaka/naechinso/domain/recommend/dto/RecommendBySenderRequestDTO.java delete mode 100644 src/main/java/com/tikitaka/naechinso/domain/recommend/dto/RecommendRequestDTO.java diff --git a/src/main/java/com/tikitaka/naechinso/domain/member/MemberController.java b/src/main/java/com/tikitaka/naechinso/domain/member/MemberController.java index 10c6365..9ff723a 100644 --- a/src/main/java/com/tikitaka/naechinso/domain/member/MemberController.java +++ b/src/main/java/com/tikitaka/naechinso/domain/member/MemberController.java @@ -33,7 +33,6 @@ public class MemberController { @GetMapping @ApiOperation(value = "유저 자신의 모든 정보를 가져온다 (AccessToken)") public CommonApiResponse getMyInformation( - HttpServletRequest request, @ApiIgnore @AuthMember Member member ) { return CommonApiResponse.of(MemberCommonResponseDTO.of(member)); @@ -109,68 +108,4 @@ public CommonApiResponse> getMyInformation( ) { return CommonApiResponse.of(memberService.findAll()); } - - @PostMapping("/recommend") - @ApiOperation(value = "다른 유저의 추천사를 작성한다 (AccessToken)") - public CommonApiResponse createRecommend( - @RequestBody RecommendMemberAcceptRequestDTO dto, - @ApiIgnore @AuthMember Member member - ) { - //로그인 상태가 아닌 경우 401 - memberService.validateToken(member); - return CommonApiResponse.of(null); - } - - - /** - * @// TODO: 2022/10/05 직업 정보가 없는 사람이 가입할 때 직업 정보 입력해야 하는 처리 필요 - * */ - @PatchMapping("/recommend/{uuid}/accept") - @ApiOperation(value = "요청받은 uuid 추천사에 자신을 추천인으로 등록한다 (삭제예정)") - public CommonApiResponse updateRecommendByUuid( - @PathVariable("uuid") String uuid, - @Valid @RequestBody RecommendMemberAcceptAndUpdateRequestDTO dto, - @ApiIgnore @AuthMember Member member - ) { - //로그인 상태가 아닌 경우 401 - memberService.validateFormalMember(member); - String phone = member.getPhone(); - RecommendResponseDTO recommendResponseDTO = recommendService.updateRecommendMemberAccept(uuid, phone, dto); - return CommonApiResponse.of(recommendResponseDTO); - } - - - /** - * 직업 인증으로 추천인을 가입시킨다 - * */ - @PatchMapping("/recommend/{uuid}/accept/job") - @ApiOperation(value = "요청받은 uuid 추천사에 자신을 추천인으로 등록하며 직업 정보를 업데이트 한다 (삭제예정)") - public CommonApiResponse updateRecommendByUuidAndJob( - @PathVariable("uuid") String uuid, - @Valid @RequestBody RecommendMemberAcceptAndUpdateRequestDTO dto, - @ApiIgnore @AuthMember Member member - ) { - //로그인 상태가 아닌 경우 401 - memberService.validateFormalMember(member); - String phone = member.getPhone(); - RecommendResponseDTO recommendResponseDTO = recommendService.updateRecommendMemberAccept(uuid, phone, dto); - return CommonApiResponse.of(recommendResponseDTO); - } - - /** - * 학교 인증으로 추천인을 가입시킨다 - * */ - @PatchMapping("/recommend/{uuid}/accept/edu") - @ApiOperation(value = "요청받은 uuid 추천사에 자신을 추천인으로 등록하며 학교 정보를 업데이트 한다 (삭제예정)") - public CommonApiResponse updateRecommendByUuidAndEdu( - @PathVariable("uuid") String uuid, - @Valid @RequestBody RecommendMemberAcceptAndUpdateRequestDTO dto, - @ApiIgnore @AuthMember Member member - ) { - //로그인 상태가 아닌 경우 401 - memberService.validateFormalMember(member); - String phone = member.getPhone(); - RecommendResponseDTO recommendResponseDTO = recommendService.updateRecommendMemberAccept(uuid, phone, dto); - return CommonApiResponse.of(recommendResponseDTO); - } } diff --git a/src/main/java/com/tikitaka/naechinso/domain/member/MemberRepository.java b/src/main/java/com/tikitaka/naechinso/domain/member/MemberRepository.java index 09dbc90..27cbfc2 100644 --- a/src/main/java/com/tikitaka/naechinso/domain/member/MemberRepository.java +++ b/src/main/java/com/tikitaka/naechinso/domain/member/MemberRepository.java @@ -10,4 +10,5 @@ public interface MemberRepository extends JpaRepository { Optional findByPhone(String phone); + } diff --git a/src/main/java/com/tikitaka/naechinso/domain/member/MemberService.java b/src/main/java/com/tikitaka/naechinso/domain/member/MemberService.java index bc61b04..056da21 100644 --- a/src/main/java/com/tikitaka/naechinso/domain/member/MemberService.java +++ b/src/main/java/com/tikitaka/naechinso/domain/member/MemberService.java @@ -31,10 +31,18 @@ public class MemberService { private final MemberDetailRepository memberDetailRepository; private final JwtTokenProvider jwtTokenProvider; + public Member findByPhone(String phone) { + return memberRepository.findByPhone(phone) + .orElseThrow(() -> new NotFoundException(ErrorCode.USER_NOT_FOUND)); + } + + public Member findByMember(Member member) { + return findByPhone(member.getPhone()); + } + public List findAll() { - List memberList = memberRepository.findAll().stream() - .map(member -> MemberCommonResponseDTO.of(member)).collect(Collectors.toList()); - return memberList; + return memberRepository.findAll().stream() + .map(MemberCommonResponseDTO::of).collect(Collectors.toList()); } @@ -54,20 +62,17 @@ public MemberCommonJoinResponseDTO joinCommonMember(String phone, MemberCommonJo return MemberCommonJoinResponseDTO.of(member, tokenResponseDTO); } + /** + * @// TODO: 2022-10-07 이상한점 수정 필요 + * */ public MemberCommonJoinResponseDTO updateCommonMember(Member authMember, MemberUpdateCommonRequestDTO dto) { //없는 유저면 404 - final String phone = authMember.getPhone(); - Optional checkMember = memberRepository.findByPhone(phone); - if(checkMember.isEmpty()) { - throw new NotFoundException(ErrorCode.USER_NOT_FOUND); - } - - Member member = checkMember.get(); + Member member = findByMember(authMember); member.updateCommon(dto); memberRepository.save(member); TokenResponseDTO tokenResponseDTO - = jwtTokenProvider.generateToken(new JwtDTO(phone, "ROLE_USER")); + = jwtTokenProvider.generateToken(new JwtDTO(member.getPhone(), "ROLE_USER")); return MemberCommonJoinResponseDTO.of(member); } @@ -102,8 +107,7 @@ public MemberDetailResponseDTO readDetail(Member member) { public MemberDetailResponseDTO createDetail(Member authMember, MemberDetailJoinRequestDTO dto) { //영속성 유지를 위한 fetch - Member member = memberRepository.findById(authMember.getId()) - .orElseThrow(() -> new NotFoundException(ErrorCode.USER_NOT_FOUND)); + Member member = findByMember(authMember); //detail 정보가 있으면 이미 가입한 회원 if (member.getDetail() != null) { @@ -117,8 +121,7 @@ public MemberDetailResponseDTO createDetail(Member authMember, MemberDetailJoinR public MemberCommonResponseDTO updateJob(Member authMember, MemberJobUpdateRequestDTO dto){ //영속성 유지를 위한 fetch - Member member = memberRepository.findById(authMember.getId()) - .orElseThrow(() -> new NotFoundException(ErrorCode.USER_NOT_FOUND)); + Member member = findByMember(authMember); member.updateJob(dto); memberRepository.save(member); @@ -127,8 +130,7 @@ public MemberCommonResponseDTO updateJob(Member authMember, MemberJobUpdateReque public MemberCommonResponseDTO updateEdu(Member authMember, MemberEduUpdateRequestDTO dto){ //영속성 유지를 위한 fetch - Member member = memberRepository.findById(authMember.getId()) - .orElseThrow(() -> new NotFoundException(ErrorCode.USER_NOT_FOUND)); + Member member = findByMember(authMember); member.updateEdu(dto); memberRepository.save(member); diff --git a/src/main/java/com/tikitaka/naechinso/domain/recommend/RecommendController.java b/src/main/java/com/tikitaka/naechinso/domain/recommend/RecommendController.java index a22cf91..7d5375d 100644 --- a/src/main/java/com/tikitaka/naechinso/domain/recommend/RecommendController.java +++ b/src/main/java/com/tikitaka/naechinso/domain/recommend/RecommendController.java @@ -1,5 +1,6 @@ package com.tikitaka.naechinso.domain.recommend; +import com.tikitaka.naechinso.domain.member.MemberService; import com.tikitaka.naechinso.domain.member.entity.Member; import com.tikitaka.naechinso.domain.recommend.dto.*; import com.tikitaka.naechinso.global.annotation.AuthMember; @@ -24,10 +25,11 @@ public class RecommendController { private final RecommendService recommendService; + private final MemberService memberService; private final JwtTokenProvider jwtTokenService; @GetMapping - @ApiOperation(value = "내 추천사 정보를 가져온다 (AccessToken 필요)") + @ApiOperation(value = "내 추천사 정보를 가져온다 (AccessToken)") public CommonApiResponse getRecommends( @ApiIgnore @AuthMember Member member) { @@ -38,14 +40,12 @@ public CommonApiResponse getRecommends( } @PostMapping - @ApiOperation(value = "추천서를 작성한 후, 추천인을 회원가입 시킨다. (삭제예정 -> 다른 유저의 추천서를 작성한다)") - public CommonApiResponse createRecommendAndJoinSender( - HttpServletRequest request, - @Valid @RequestBody RecommendAndJoinRequestDTO dto) - { - String phone = jwtTokenService.parsePhoneByRegisterToken(request); - - RecommendResponseDTO recommendResponseDTO = recommendService.createRecommendJoin(phone, dto); + @ApiOperation(value = "다른 유저의 추천사를 작성한다 (AccessToken)") + public CommonApiResponse createRecommend( + @Valid @RequestBody RecommendBySenderRequestDTO dto, + @ApiIgnore @AuthMember Member member + ) { + RecommendResponseDTO recommendResponseDTO = recommendService.createRecommend(member, dto); return CommonApiResponse.of(recommendResponseDTO); } @@ -61,47 +61,38 @@ public CommonApiResponse> getAllRecommends( } @PostMapping("/request") - @ApiOperation(value = "다른 유저에게 추천서 작성을 요청한다 (RegisterToken)") + @ApiOperation(value = "다른 유저에게 추천서 작성을 요청한다 (AccessToken)") public CommonApiResponse createRecommendRequest( - HttpServletRequest request, - @Valid @RequestBody RecommendRequestDTO dto) + @ApiIgnore @AuthMember Member member) { - String phone = jwtTokenService.parsePhoneByRegisterToken(request); - RecommendResponseDTO recommendResponseDTO = recommendService.createRecommendRequest(phone, dto); + RecommendResponseDTO recommendResponseDTO = recommendService.createRecommendRequest(member); return CommonApiResponse.of(recommendResponseDTO); } - - - //제일 아래에 있어야함 @GetMapping("/{uuid}") - @ApiOperation(value = "추천 요청받은 uuid 를 가진 추천사 정보를 가져온다 (Register / AccessToken)") + @ApiOperation(value = "해당 UUID 를 가진 추천사 정보를 가져온다 (Register / AccessToken)") public CommonApiResponse getRecommendByUuid( HttpServletRequest request, @PathVariable("uuid") String uuid) { //토큰 장착 확인 String phone = jwtTokenService.parsePhoneByRegisterToken(request); - RecommendResponseDTO recommendResponseDTO = RecommendResponseDTO.of(recommendService.findByUuid(uuid)); return CommonApiResponse.of(recommendResponseDTO); } @PatchMapping("/{uuid}/accept") - @ApiOperation(value = "요청받은 uuid 추천사에 자신을 추천인으로 등록한 후 임시 회원으로 가입한다 (RegisterToken)") + @ApiOperation(value = "해당 UUID 추천사에 자신을 추천인으로 등록한다 (AccessToken)") public CommonApiResponse updateRecommendByUuid( - HttpServletRequest request, + @ApiIgnore @AuthMember Member member, @PathVariable("uuid") String uuid, - @Valid @RequestBody RecommendAcceptWithJoinRequestDTO dto) + @Valid @RequestBody RecommendAcceptRequestDTO dto) { - //토큰 장착 확인 - String phone = jwtTokenService.parsePhoneByRegisterToken(request); - - RecommendResponseDTO recommendResponseDTO = recommendService.updateRecommendRequestWithJoin(uuid, phone, dto); + RecommendResponseDTO recommendResponseDTO = recommendService.acceptRecommendByUuid(member, uuid, dto); return CommonApiResponse.of(recommendResponseDTO); } } diff --git a/src/main/java/com/tikitaka/naechinso/domain/recommend/RecommendRepository.java b/src/main/java/com/tikitaka/naechinso/domain/recommend/RecommendRepository.java index baba456..9e03e62 100644 --- a/src/main/java/com/tikitaka/naechinso/domain/recommend/RecommendRepository.java +++ b/src/main/java/com/tikitaka/naechinso/domain/recommend/RecommendRepository.java @@ -27,4 +27,6 @@ public interface RecommendRepository extends JpaRepository { Boolean existsByReceiverPhone(String phone); Boolean existsByReceiverPhoneAndSenderNotNull(String phone); + + Boolean existsBySenderPhoneAndReceiverPhone(String senderPhone, String receiverPhone); } diff --git a/src/main/java/com/tikitaka/naechinso/domain/recommend/RecommendService.java b/src/main/java/com/tikitaka/naechinso/domain/recommend/RecommendService.java index 21900a7..12032fd 100644 --- a/src/main/java/com/tikitaka/naechinso/domain/recommend/RecommendService.java +++ b/src/main/java/com/tikitaka/naechinso/domain/recommend/RecommendService.java @@ -1,6 +1,7 @@ package com.tikitaka.naechinso.domain.recommend; import com.tikitaka.naechinso.domain.member.MemberRepository; +import com.tikitaka.naechinso.domain.member.MemberService; import com.tikitaka.naechinso.domain.member.dto.MemberJobUpdateRequestDTO; import com.tikitaka.naechinso.domain.recommend.dto.RecommendMemberAcceptRequestDTO; import com.tikitaka.naechinso.domain.member.entity.Member; @@ -8,8 +9,10 @@ import com.tikitaka.naechinso.domain.recommend.entity.Recommend; import com.tikitaka.naechinso.global.error.ErrorCode; import com.tikitaka.naechinso.global.error.exception.BadRequestException; +import com.tikitaka.naechinso.global.error.exception.InternalServerException; import com.tikitaka.naechinso.global.error.exception.NotFoundException; import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; @@ -18,6 +21,7 @@ import java.util.Optional; import java.util.stream.Collectors; +@Slf4j @Service @RequiredArgsConstructor @Transactional @@ -25,6 +29,7 @@ public class RecommendService { private final RecommendRepository recommendRepository; private final MemberRepository memberRepository; + private final MemberService memberService; /** * 추천사 정보를 가져온다 @@ -46,21 +51,24 @@ public List findAllRecommendReceivedListBasicByPhone(Strin /** * 임시회원으로 등록하며 가입하지 않은 임의의 유저 추천사를 작성한다 * */ - public RecommendResponseDTO createRecommendJoin(String senderPhone, RecommendAndJoinRequestDTO dto) { - //멤버가 이미 있으면 종료 - Optional checkSender = memberRepository.findByPhone(senderPhone); - if (checkSender.isPresent()) { - throw new BadRequestException(ErrorCode.USER_ALREADY_EXIST); - } + public RecommendResponseDTO createRecommend(Member authMember, RecommendBySenderRequestDTO dto) { + Member sender = memberService.findByMember(authMember); + String senderPhone = sender.getPhone(); + String receiverPhone = dto.getPhone(); - //자기 자신을 추천하면 종료 - if (senderPhone == dto.getReceiverPhone()) { - throw new BadRequestException(ErrorCode.CANNOT_RECOMMEND_MYSELF); - } + //자기 자신을 추천하면 종료 + if (senderPhone.equals(receiverPhone)) { + throw new BadRequestException(ErrorCode.CANNOT_RECOMMEND_MYSELF); + } - Member sender = dto.toSender(senderPhone); + //동일한 상대를 중복 추천할 수 없음 + if (existsBySenderPhoneAndReceiverPhone(senderPhone, receiverPhone)) { + throw new BadRequestException(ErrorCode.RECOMMEND_ALREADY_EXIST); + } - Member receiver = memberRepository.findByPhone(dto.getReceiverPhone()) + try { + //추천 상대가 이미 가입했다면 영속성 엔티티를 가져옴 + Member receiver = memberRepository.findByPhone(dto.getPhone()) .orElse(null); Recommend recommend = Recommend.builder() @@ -73,157 +81,77 @@ public RecommendResponseDTO createRecommendJoin(String senderPhone, RecommendAnd .senderJobPart(sender.getJobPart()) .senderJobLocation(sender.getJobLocation()) .receiver(receiver) - .receiverPhone(dto.getReceiverPhone()) - .receiverName(dto.getReceiverName()) - .receiverAge(dto.getReceiverAge()) + .receiverPhone(dto.getPhone()) + .receiverName(dto.getName()) + .receiverAge(dto.getAge()) + .receiverGender(dto.getGender()) .receiverAppeal(dto.getAppeal()) - .receiverGender(dto.getReceiverGender()) .receiverMeet(dto.getMeet()) .receiverPersonality(dto.getPersonality()) .receiverPeriod(dto.getPeriod()) .build(); - memberRepository.save(sender); recommendRepository.save(recommend); - return RecommendResponseDTO.of(recommend); + } catch (Exception e) { + log.error("추천사 작성 실패"); + throw new InternalServerException(ErrorCode.CANNOT_CREATE_RECOMMEND); + } } /** * 내 추천사 작성을 요청한다 * */ - public RecommendResponseDTO createRecommendRequest(String receiverPhone, RecommendRequestDTO dto) { + public RecommendResponseDTO createRecommendRequest(Member authMember) { //이미 추천사 요청을 보냄 - if (existsByReceiverPhone(receiverPhone)) { - throw(new NotFoundException(ErrorCode.RECOMMEND_ALREADY_EXIST)); + if (existsByReceiverPhone(authMember.getPhone())) { + throw(new NotFoundException(ErrorCode.RECOMMEND_REQUEST_ALREADY_EXIST)); } + try { + Member receiver = memberService.findByMember(authMember); + Recommend recommend = Recommend.builder() + .sender(null) + .receiver(receiver) + .receiverPhone(receiver.getPhone()) + .receiverName(receiver.getName()) + .receiverAge(receiver.getAge()) + .receiverGender(receiver.getGender()) + .build(); - Member receiver = dto.toReceiver(receiverPhone); - Recommend recommend = Recommend.builder() - .sender(null) - .receiver(receiver) - .receiverPhone(receiverPhone) - .receiverName(dto.getName()) - .receiverAge(dto.getAge()) - .receiverGender(dto.getGender()) - .build(); - - memberRepository.save(receiver); - recommendRepository.save(recommend); + recommendRepository.save(recommend); - return RecommendResponseDTO.of(recommend); + return RecommendResponseDTO.of(recommend); + } catch (Exception e) { + log.error("추천사 작성 요청 생성 실패"); + throw new InternalServerException(ErrorCode.CANNOT_CREATE_RECOMMEND_REQUEST); + } } /** - * 임시회원으로 가입하며 해당 uuid 추천사에 자신을 등록한다 + * 해당 uuid 추천사에 자신을 등록한다 * */ - public RecommendResponseDTO updateRecommendRequestWithJoin(String uuid, String senderPhone, RecommendAcceptWithJoinRequestDTO dto) { + public RecommendResponseDTO acceptRecommendByUuid(Member authMember, String uuid, RecommendAcceptRequestDTO dto) { Recommend recommend = findByUuidAndReceiverNotNull(uuid); - - //자기 자신을 추천하면 종료 - if (senderPhone.equals(recommend.getReceiverPhone())) { - throw new BadRequestException(ErrorCode.CANNOT_RECOMMEND_MYSELF); - } + Member sender = memberService.findByMember(authMember); //이미 작성된 추천사 엔티티면 종료 if (recommend.getSender() != null) { throw new BadRequestException(ErrorCode.RECOMMEND_SENDER_ALREADY_EXIST); } - //유저가 없으면 회원가입 시킴, 있으면 그대로 사용 - Optional checkSender = memberRepository.findByPhone(senderPhone); - if(checkSender.isPresent()) { - throw new BadRequestException(ErrorCode.USER_ALREADY_EXIST); - } - Member sender = dto.toSender(senderPhone); - - //유저 정보 업데이트, 가입 정보가 이미 있다면 무시됨, 없으면 생성 - recommend.update(sender, dto); - - memberRepository.save(sender); - recommendRepository.save(recommend); - - return RecommendResponseDTO.of(recommend); - } - - /** - * 추천사 작성 유저가 정회원일 경우 해당 유저 정보로 uuid 에 해당하는 추천사를 등록한다 - * */ - public RecommendResponseDTO updateRecommendMemberAccept(String uuid, String senderPhone, RecommendMemberAcceptRequestDTO dto) { - - Recommend recommend = findByUuidAndReceiverNotNull(uuid); - //자기 자신을 추천하면 종료 - if (senderPhone.equals(recommend.getReceiverPhone())) { + if (sender.getPhone().equals(recommend.getReceiverPhone())) { throw new BadRequestException(ErrorCode.CANNOT_RECOMMEND_MYSELF); } - //이미 작성된 추천사 엔티티면 종료 - if (recommend.getSender() != null) { - throw new BadRequestException(ErrorCode.RECOMMEND_SENDER_ALREADY_EXIST); - } - - //유저가 없으면 400 - Member sender = memberRepository.findByPhone(senderPhone) - .orElseThrow(() -> new BadRequestException(ErrorCode.USER_NOT_FOUND)); - - recommend.update(sender, dto); - - memberRepository.save(sender); + //추천사 업데이트 + recommend.update(dto); recommendRepository.save(recommend); return RecommendResponseDTO.of(recommend); } - /** - * 추천사 작성 유저가 임시회원 이상일 경우 - * 해당 유저 정보로 uuid 에 해당하는 추천사를 등록하며 - * 직업 정보를 업데이트 한다 - * */ - public RecommendResponseDTO updateRecommendMemberAccept(String uuid, String senderPhone, RecommendMemberAcceptAndUpdateRequestDTO dto) { - - Recommend recommend = findByUuidAndReceiverNotNull(uuid); - - //자기 자신을 추천하면 종료 - if (senderPhone.equals(recommend.getReceiverPhone())) { - throw new BadRequestException(ErrorCode.CANNOT_RECOMMEND_MYSELF); - } - - //이미 작성된 추천사 엔티티면 종료 - if (recommend.getSender() != null) { - throw new BadRequestException(ErrorCode.RECOMMEND_SENDER_ALREADY_EXIST); - } - - //유저가 없으면 400 - Member sender = memberRepository.findByPhone(senderPhone) - .orElseThrow(() -> new BadRequestException(ErrorCode.USER_NOT_FOUND)); - - //직업 정보가 있다면 업데이트 - if (dto.getJob() != null) { - MemberJobUpdateRequestDTO jobUpdateRequestDTO = MemberJobUpdateRequestDTO.builder() - .jobLocation(dto.getJob().getJobLocation()) - .jobPart(dto.getJob().getJobLocation()) - .jobName(dto.getJob().getJobName()) - .build(); - sender.updateJob(jobUpdateRequestDTO); - } - - if (dto.getEdu() != null) { - RecommendMemberAcceptRequestDTO updateDTO2 = RecommendMemberAcceptRequestDTO.builder() - .appeal(dto.getAppeal()) - .meet(dto.getMeet()) - .period(dto.getPeriod()) - .personality(dto.getPersonality()) - .build(); - recommend.update(sender, updateDTO2); - } - - memberRepository.save(sender); - recommendRepository.save(recommend); - - return RecommendResponseDTO.of(recommend); - } public List findAll() { List recommendResponseDTOList = new ArrayList<>(); @@ -265,4 +193,10 @@ public Boolean existsByReceiverPhoneAndSenderNotNull(String phone){ return recommendRepository.existsByReceiverPhoneAndSenderNotNull(phone); } + public Boolean existsBySenderPhoneAndReceiverPhone(String senderPhone, String receiverPhone){ + return recommendRepository.existsBySenderPhoneAndReceiverPhone(senderPhone, receiverPhone); + } + + + } diff --git a/src/main/java/com/tikitaka/naechinso/domain/recommend/dto/RecommendAcceptRequestDTO.java b/src/main/java/com/tikitaka/naechinso/domain/recommend/dto/RecommendAcceptRequestDTO.java new file mode 100644 index 0000000..3a5e54e --- /dev/null +++ b/src/main/java/com/tikitaka/naechinso/domain/recommend/dto/RecommendAcceptRequestDTO.java @@ -0,0 +1,33 @@ +package com.tikitaka.naechinso.domain.recommend.dto; + +import com.tikitaka.naechinso.domain.member.constant.Gender; +import com.tikitaka.naechinso.domain.member.entity.Member; +import com.tikitaka.naechinso.global.annotation.Enum; +import io.swagger.annotations.ApiModelProperty; +import lombok.*; + +import javax.validation.constraints.*; + +@AllArgsConstructor +@NoArgsConstructor +@Getter +@Builder +@ToString +public class RecommendAcceptRequestDTO { + + @ApiModelProperty(example = "CMC 에서") + @NotBlank(message = "만나게 된 계기를 입력해주세요") + private String meet; + + @ApiModelProperty(example = "최고") + @NotBlank(message = "친구의 성격 키워드를 입력해주세요") + private String personality; + + @ApiModelProperty(example = "짱") + @NotBlank(message = "친구의 매력을 입력해주세요") + private String appeal; + + @ApiModelProperty(example = "1년") + @NotBlank(message = "만난 기간을 입력해주세요") + private String period; +} diff --git a/src/main/java/com/tikitaka/naechinso/domain/recommend/dto/RecommendAcceptWithJoinRequestDTO.java b/src/main/java/com/tikitaka/naechinso/domain/recommend/dto/RecommendAcceptWithJoinRequestDTO.java deleted file mode 100644 index 1fe211c..0000000 --- a/src/main/java/com/tikitaka/naechinso/domain/recommend/dto/RecommendAcceptWithJoinRequestDTO.java +++ /dev/null @@ -1,106 +0,0 @@ -package com.tikitaka.naechinso.domain.recommend.dto; - -import com.tikitaka.naechinso.domain.member.constant.Gender; -import com.tikitaka.naechinso.domain.member.entity.Member; -import com.tikitaka.naechinso.global.annotation.Enum; -import io.swagger.annotations.ApiModelProperty; -import lombok.*; - -import javax.validation.constraints.*; - -@AllArgsConstructor -@NoArgsConstructor -@Getter -@Builder -@ToString -public class RecommendAcceptWithJoinRequestDTO { - @ApiModelProperty(example = "닉") - @NotBlank(message = "이름을 입력해주세요") - private String name; - - @ApiModelProperty(example = "M") - @Enum(enumClass = Gender.class, message = "성별 입력이 올바르지 않습니다. M 또는 W가 필요합니다") - private Gender gender; - - @ApiModelProperty(example = "25") - @Min(value = 25, message = "25-33세까지만 가입 가능합니다") - @Max(value = 33, message = "25-33세까지만 가입 가능합니다") - private int age; - - @NotNull(message = "서비스 이용약관 동의가 필요합니다") - @AssertTrue(message = "서비스 이용약관 동의가 필요합니다") - private boolean acceptsService; - - @NotNull(message = "개인정보 이용 동의가 필요합니다") - @AssertTrue(message = "개인정보 이용 동의가 필요합니다") - private boolean acceptsInfo; - - @NotNull(message = "종교 정보 제공 동의가 필요합니다") - @AssertTrue(message = "종교 정보 제공 동의가 필요합니다") - private boolean acceptsReligion; - - @NotNull(message = "위치 정보 제공 동의 여부가 필요합니다") - private boolean acceptsLocation; - - @NotNull(message = "마케팅 동의 여부가 필요합니다") - private boolean acceptsMarketing; - - @ApiModelProperty(example = "카카오") - @NotBlank(message = "직장명을 입력해주세요") - private String jobName; - - @ApiModelProperty(example = "개발자") - @NotBlank(message = "직장 부서를 입력해주세요") - private String jobPart; - - @ApiModelProperty(example = "판교") - @NotBlank(message = "직장 위치를 입력해주세요") - private String jobLocation; - - - @ApiModelProperty(example = "박스") - @NotBlank(message = "친구의 이름을 입력해주세요") - private String receiverName; - - @ApiModelProperty(example = "M") - @Enum(enumClass = Gender.class, message = "친구의 성별 입력이 올바르지 않습니다. M 또는 W가 필요합니다") - private Gender receiverGender; - - @ApiModelProperty(example = "25") - @Min(value = 25, message = "25-33세까지만 추천 및 가입 가능합니다") - @Max(value = 33, message = "25-33세까지만 추천 및 가입 가능합니다") - private int receiverAge; - - @ApiModelProperty(example = "CMC 에서") - @NotBlank(message = "만나게 된 계기를 입력해주세요") - private String meet; - - @ApiModelProperty(example = "최고") - @NotBlank(message = "친구의 성격 키워드를 입력해주세요") - private String personality; - - @ApiModelProperty(example = "짱") - @NotBlank(message = "친구의 매력을 입력해주세요") - private String appeal; - - @ApiModelProperty(example = "1년") - @NotBlank(message = "만난 기간을 입력해주세요") - private String period; - - public Member toSender(String phone){ - return Member.builder() - .phone(phone) - .name(this.name) - .gender(this.gender) - .age(this.age) - .acceptsService(this.acceptsService) - .acceptsInfo(this.acceptsInfo) - .acceptsReligion(this.acceptsReligion) - .acceptsLocation(this.acceptsLocation) - .acceptsMarketing(this.acceptsMarketing) - .jobName(this.jobName) - .jobPart(this.jobPart) - .jobLocation(this.jobLocation) - .build(); - } -} diff --git a/src/main/java/com/tikitaka/naechinso/domain/recommend/dto/RecommendAndJoinRequestDTO.java b/src/main/java/com/tikitaka/naechinso/domain/recommend/dto/RecommendAndJoinRequestDTO.java deleted file mode 100644 index 0250a7f..0000000 --- a/src/main/java/com/tikitaka/naechinso/domain/recommend/dto/RecommendAndJoinRequestDTO.java +++ /dev/null @@ -1,152 +0,0 @@ -package com.tikitaka.naechinso.domain.recommend.dto; - -import com.tikitaka.naechinso.domain.member.constant.Gender; -import com.tikitaka.naechinso.domain.member.dto.MemberEduUpdateRequestDTO; -import com.tikitaka.naechinso.domain.member.dto.MemberJobUpdateRequestDTO; -import com.tikitaka.naechinso.domain.member.entity.Member; -import com.tikitaka.naechinso.global.annotation.Enum; -import io.swagger.annotations.ApiModelProperty; -import lombok.*; - -import javax.validation.constraints.*; - -/** 가입하지 않은 멤버가 추천사를 써줄 때 요청 DTO - * @author gengminy 221001 -*/ -@AllArgsConstructor -@NoArgsConstructor -@Getter -@Builder -@ToString -public class RecommendAndJoinRequestDTO { - @ApiModelProperty(example = "닉") - @NotBlank(message = "이름을 입력해주세요") - private String name; - - @ApiModelProperty(example = "M") - @Enum(enumClass = Gender.class, message = "성별 입력이 올바르지 않습니다. M 또는 W가 필요합니다") - private Gender gender; - - @ApiModelProperty(example = "25") - @Min(value = 25, message = "25-33세까지만 가입 가능합니다") - @Max(value = 33, message = "25-33세까지만 가입 가능합니다") - private int age; - - @NotNull(message = "서비스 이용약관 동의가 필요합니다") - @AssertTrue(message = "서비스 이용약관 동의가 필요합니다") - private boolean acceptsService; - - @NotNull(message = "개인정보 이용 동의가 필요합니다") - @AssertTrue(message = "개인정보 이용 동의가 필요합니다") - private boolean acceptsInfo; - - @NotNull(message = "종교 정보 제공 동의가 필요합니다") - @AssertTrue(message = "종교 정보 제공 동의가 필요합니다") - private boolean acceptsReligion; - - @NotNull(message = "위치 정보 제공 동의 여부가 필요합니다") - private boolean acceptsLocation; - - @NotNull(message = "마케팅 동의 여부가 필요합니다") - private boolean acceptsMarketing; - - private MemberEduUpdateRequestDTO edu; - - private MemberJobUpdateRequestDTO job; - - - - - - @ApiModelProperty(example = "01099999999") - @NotBlank(message = "친구의 전화번호를 입력해주세요") - @Pattern(regexp = "[0-9]{10,11}", message = "하이픈 없는 10~11자리 숫자를 입력해주세요") - private String receiverPhone; - - @ApiModelProperty(example = "박스") - @NotBlank(message = "친구의 이름을 입력해주세요") - private String receiverName; - - @ApiModelProperty(example = "M") - @Enum(enumClass = Gender.class, message = "친구의 성별 입력이 올바르지 않습니다. M 또는 W가 필요합니다") - private Gender receiverGender; - - @ApiModelProperty(example = "25") - @Min(value = 25, message = "25-33세까지만 추천 및 가입 가능합니다") - @Max(value = 33, message = "25-33세까지만 추천 및 가입 가능합니다") - private int receiverAge; - - @ApiModelProperty(example = "CMC 에서") - @NotBlank(message = "만나게 된 계기를 입력해주세요") - private String meet; - - @ApiModelProperty(example = "최고") - @NotBlank(message = "친구의 성격 키워드를 입력해주세요") - private String personality; - - @ApiModelProperty(example = "짱") - @NotBlank(message = "친구의 매력을 입력해주세요") - private String appeal; - - @ApiModelProperty(example = "1년") - @NotBlank(message = "만난 기간을 입력해주세요") - private String period; - - public Member toSender(String phone){ - Member.MemberBuilder builder = Member.builder(); - if (this.job != null) { - builder.jobName(this.job.getJobName()) - .jobPart(this.job.getJobPart()) - .jobLocation(this.job.getJobLocation()) - .jobPicture(this.job.getJobPicture()); - } - - if (this.edu != null) { - builder.eduName(this.edu.getEduName()) - .eduMajor(this.edu.getEduMajor()) - .eduLevel(this.edu.getEduMajor()) - .eduPicture(this.edu.getEduPicture()); - } - - return builder - .phone(phone) - .name(this.name) - .gender(this.gender) - .age(this.age) - .acceptsService(this.acceptsService) - .acceptsInfo(this.acceptsInfo) - .acceptsReligion(this.acceptsReligion) - .acceptsLocation(this.acceptsLocation) - .acceptsMarketing(this.acceptsMarketing) - .build(); - } - - public Member toReceiver(String phone){ - Member.MemberBuilder builder = Member.builder(); - if (job != null) { - builder.jobName(this.job.getJobName()) - .jobPart(this.job.getJobPart()) - .jobLocation(this.job.getJobLocation()) - .jobPicture(this.job.getJobPicture()); - } - - if (edu != null) { - builder.eduName(this.edu.getEduName()) - .eduMajor(this.edu.getEduMajor()) - .eduLevel(this.edu.getEduMajor()) - .eduPicture(this.edu.getEduPicture()); - } - - return Member.builder() - .phone(phone) - .name(this.name) - .gender(this.gender) - .age(this.age) - .acceptsService(this.acceptsService) - .acceptsInfo(this.acceptsInfo) - .acceptsReligion(this.acceptsReligion) - .acceptsLocation(this.acceptsLocation) - .acceptsMarketing(this.acceptsMarketing) - .build(); - } -} diff --git a/src/main/java/com/tikitaka/naechinso/domain/recommend/dto/RecommendBySenderRequestDTO.java b/src/main/java/com/tikitaka/naechinso/domain/recommend/dto/RecommendBySenderRequestDTO.java new file mode 100644 index 0000000..54bfb89 --- /dev/null +++ b/src/main/java/com/tikitaka/naechinso/domain/recommend/dto/RecommendBySenderRequestDTO.java @@ -0,0 +1,146 @@ +package com.tikitaka.naechinso.domain.recommend.dto; + +import com.tikitaka.naechinso.domain.member.constant.Gender; +import com.tikitaka.naechinso.domain.member.dto.MemberEduUpdateRequestDTO; +import com.tikitaka.naechinso.domain.member.dto.MemberJobUpdateRequestDTO; +import com.tikitaka.naechinso.domain.member.entity.Member; +import com.tikitaka.naechinso.global.annotation.Enum; +import io.swagger.annotations.ApiModelProperty; +import lombok.*; + +import javax.validation.constraints.*; + +/** 가입하지 않은 멤버가 추천사를 써줄 때 요청 DTO + * @author gengminy 221001 +*/ +@AllArgsConstructor +@NoArgsConstructor +@Getter +@Builder +@ToString +public class RecommendBySenderRequestDTO { +// @ApiModelProperty(example = "닉") +// @NotBlank(message = "이름을 입력해주세요") +// private String name; +// +// @ApiModelProperty(example = "M") +// @Enum(enumClass = Gender.class, message = "성별 입력이 올바르지 않습니다. M 또는 W가 필요합니다") +// private Gender gender; +// +// @ApiModelProperty(example = "25") +// @Min(value = 25, message = "25-33세까지만 가입 가능합니다") +// @Max(value = 33, message = "25-33세까지만 가입 가능합니다") +// private int age; +// +// @NotNull(message = "서비스 이용약관 동의가 필요합니다") +// @AssertTrue(message = "서비스 이용약관 동의가 필요합니다") +// private boolean acceptsService; +// +// @NotNull(message = "개인정보 이용 동의가 필요합니다") +// @AssertTrue(message = "개인정보 이용 동의가 필요합니다") +// private boolean acceptsInfo; +// +// @NotNull(message = "종교 정보 제공 동의가 필요합니다") +// @AssertTrue(message = "종교 정보 제공 동의가 필요합니다") +// private boolean acceptsReligion; +// +// @NotNull(message = "위치 정보 제공 동의 여부가 필요합니다") +// private boolean acceptsLocation; +// +// @NotNull(message = "마케팅 동의 여부가 필요합니다") +// private boolean acceptsMarketing; +// +// private MemberEduUpdateRequestDTO edu; +// +// private MemberJobUpdateRequestDTO job; +// +// +// + + + @ApiModelProperty(example = "01099999999") + @NotBlank(message = "친구의 전화번호를 입력해주세요") + @Pattern(regexp = "[0-9]{10,11}", message = "하이픈 없는 10~11자리 숫자를 입력해주세요") + private String phone; + + @ApiModelProperty(example = "박스") + @NotBlank(message = "친구의 이름을 입력해주세요") + private String name; + + @ApiModelProperty(example = "M") + @Enum(enumClass = Gender.class, message = "친구의 성별 입력이 올바르지 않습니다. M 또는 W가 필요합니다") + private Gender gender; + + @ApiModelProperty(example = "25") + @Min(value = 25, message = "25-33세까지만 추천 및 가입 가능합니다") + @Max(value = 33, message = "25-33세까지만 추천 및 가입 가능합니다") + private int age; + + @ApiModelProperty(example = "CMC 에서") + @NotBlank(message = "만나게 된 계기를 입력해주세요") + private String meet; + + @ApiModelProperty(example = "최고") + @NotBlank(message = "친구의 성격 키워드를 입력해주세요") + private String personality; + + @ApiModelProperty(example = "짱") + @NotBlank(message = "친구의 매력을 입력해주세요") + private String appeal; + + @ApiModelProperty(example = "1년") + @NotBlank(message = "만난 기간을 입력해주세요") + private String period; +// +// public Member toSender(String phone){ +// Member.MemberBuilder builder = Member.builder(); +// if (this.job != null) { +// builder.jobName(this.job.getJobName()) +// .jobPart(this.job.getJobPart()) +// .jobLocation(this.job.getJobLocation()) +// .jobPicture(this.job.getJobPicture()); +// } +// +// if (this.edu != null) { +// builder.eduName(this.edu.getEduName()) +// .eduMajor(this.edu.getEduMajor()) +// .eduLevel(this.edu.getEduMajor()) +// .eduPicture(this.edu.getEduPicture()); +// } +// +// return builder +// .phone(phone) +// .name(this.name) +// .gender(this.gender) +// .age(this.age) +// .acceptsService(this.acceptsService) +// .acceptsInfo(this.acceptsInfo) +// .acceptsReligion(this.acceptsReligion) +// .acceptsLocation(this.acceptsLocation) +// .acceptsMarketing(this.acceptsMarketing) +// .build(); +// } + + public Member toReceiver(String phone){ +// if (job != null) { +// builder.jobName(this.job.getJobName()) +// .jobPart(this.job.getJobPart()) +// .jobLocation(this.job.getJobLocation()) +// .jobPicture(this.job.getJobPicture()); +// } +// +// if (edu != null) { +// builder.eduName(this.edu.getEduName()) +// .eduMajor(this.edu.getEduMajor()) +// .eduLevel(this.edu.getEduMajor()) +// .eduPicture(this.edu.getEduPicture()); +// } + + return Member.builder() + .phone(phone) + .name(this.name) + .gender(this.gender) + .age(this.age) + .build(); + } +} diff --git a/src/main/java/com/tikitaka/naechinso/domain/recommend/dto/RecommendRequestDTO.java b/src/main/java/com/tikitaka/naechinso/domain/recommend/dto/RecommendRequestDTO.java deleted file mode 100644 index c3e5825..0000000 --- a/src/main/java/com/tikitaka/naechinso/domain/recommend/dto/RecommendRequestDTO.java +++ /dev/null @@ -1,64 +0,0 @@ -package com.tikitaka.naechinso.domain.recommend.dto; - -import com.tikitaka.naechinso.domain.member.constant.Gender; -import com.tikitaka.naechinso.domain.member.entity.Member; -import com.tikitaka.naechinso.global.annotation.Enum; -import io.swagger.annotations.ApiModelProperty; -import lombok.*; - -import javax.persistence.Column; -import javax.persistence.GeneratedValue; -import javax.validation.constraints.*; -import java.util.UUID; - -@AllArgsConstructor -@NoArgsConstructor -@Getter -@Builder -@ToString -public class RecommendRequestDTO { - @ApiModelProperty(example = "닉") - @NotBlank(message = "유저 이름을 입력해주세요") - private String name; - - @ApiModelProperty(example = "M") - @Enum(enumClass = Gender.class, message = "유저의 성별 입력이 올바르지 않습니다. M 또는 W가 필요합니다") - private Gender gender; - - @ApiModelProperty(example = "25") - @Min(value = 25, message = "25-33세까지만 추천 및 가입 가능합니다") - @Max(value = 33, message = "25-33세까지만 추천 및 가입 가능합니다") - private int age; - - @NotNull(message = "서비스 이용약관 동의가 필요합니다") - @AssertTrue(message = "서비스 이용약관 동의가 필요합니다") - private boolean acceptsService; - - @NotNull(message = "개인정보 이용 동의가 필요합니다") - @AssertTrue(message = "개인정보 이용 동의가 필요합니다") - private boolean acceptsInfo; - - @NotNull(message = "종교 정보 제공 동의가 필요합니다") - @AssertTrue(message = "종교 정보 제공 동의가 필요합니다") - private boolean acceptsReligion; - - @NotNull(message = "위치 정보 제공 동의 여부가 필요합니다") - private boolean acceptsLocation; - - @NotNull(message = "마케팅 동의 여부가 필요합니다") - private boolean acceptsMarketing; - - public Member toReceiver(String phone) { - return Member.builder() - .name(this.name) - .phone(phone) - .gender(this.gender) - .age(this.age) - .acceptsService(this.acceptsService) - .acceptsInfo(this.acceptsInfo) - .acceptsReligion(this.acceptsReligion) - .acceptsLocation(this.acceptsLocation) - .acceptsMarketing(this.acceptsMarketing) - .build(); - } -} diff --git a/src/main/java/com/tikitaka/naechinso/domain/recommend/entity/Recommend.java b/src/main/java/com/tikitaka/naechinso/domain/recommend/entity/Recommend.java index 794a8a4..b0eefcf 100644 --- a/src/main/java/com/tikitaka/naechinso/domain/recommend/entity/Recommend.java +++ b/src/main/java/com/tikitaka/naechinso/domain/recommend/entity/Recommend.java @@ -3,7 +3,7 @@ import com.fasterxml.jackson.annotation.JsonIgnore; import com.tikitaka.naechinso.domain.member.constant.Gender; import com.tikitaka.naechinso.domain.member.entity.Member; -import com.tikitaka.naechinso.domain.recommend.dto.RecommendAcceptWithJoinRequestDTO; +import com.tikitaka.naechinso.domain.recommend.dto.RecommendAcceptRequestDTO; import com.tikitaka.naechinso.domain.recommend.dto.RecommendMemberAcceptRequestDTO; import com.tikitaka.naechinso.global.config.entity.BaseEntity; import lombok.*; @@ -92,9 +92,12 @@ public class Recommend extends BaseEntity { @Column(name = "rec_period") private String receiverPeriod; - public void update(Member sender, RecommendAcceptWithJoinRequestDTO requestDTO) { - updateSender(sender); - updateReceiver(requestDTO); + + public void update(RecommendAcceptRequestDTO requestDTO) { + this.receiverAppeal = requestDTO.getAppeal(); + this.receiverMeet = requestDTO.getMeet(); + this.receiverPersonality = requestDTO.getPersonality(); + this.receiverPeriod = requestDTO.getPeriod(); } public void update(Member sender, RecommendMemberAcceptRequestDTO requestDTO) { @@ -115,12 +118,4 @@ public void updateSender(Member sender) { this.senderJobPart = sender.getJobPart(); this.senderJobLocation = sender.getJobLocation(); } - - public void updateReceiver(RecommendAcceptWithJoinRequestDTO requestDTO) { - this.receiverAppeal = requestDTO.getAppeal(); - this.receiverMeet = requestDTO.getMeet(); - this.receiverPersonality = requestDTO.getPersonality(); - this.receiverPeriod = requestDTO.getPeriod(); - } - } diff --git a/src/main/java/com/tikitaka/naechinso/domain/sms/SmsCertificationController.java b/src/main/java/com/tikitaka/naechinso/domain/sms/SmsCertificationController.java index 7989d8a..ac19f56 100644 --- a/src/main/java/com/tikitaka/naechinso/domain/sms/SmsCertificationController.java +++ b/src/main/java/com/tikitaka/naechinso/domain/sms/SmsCertificationController.java @@ -5,6 +5,7 @@ import com.tikitaka.naechinso.global.config.CommonApiResponse; import com.tikitaka.naechinso.domain.sms.dto.SmsCertificationRequestDTO; import com.tikitaka.naechinso.domain.sms.dto.SmsVerificationCodeRequestDTO; +import io.swagger.annotations.ApiOperation; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; import org.springframework.web.bind.annotation.PostMapping; @@ -22,12 +23,14 @@ public class SmsCertificationController { private final SmsCertificationService smsCertificationService; @PostMapping("/send") + @ApiOperation(value = "인증번호가 담긴 문자를 보낸다") public CommonApiResponse sendMessageWithVerificationCode(@Valid @RequestBody SmsVerificationCodeRequestDTO dto) { String result = smsCertificationService.sendVerificationMessage(dto.getPhoneNumber()); return CommonApiResponse.of(result); } @PostMapping("/verify") + @ApiOperation(value = "인증번호를 입력하여 인증한다") public CommonApiResponse verifyCode(@RequestBody @Valid SmsCertificationRequestDTO dto) { SmsCertificationSuccessResponseDTO responseDTO = smsCertificationService.verifyCode(dto); return CommonApiResponse.of(responseDTO); diff --git a/src/main/java/com/tikitaka/naechinso/global/config/security/SecurityConfig.java b/src/main/java/com/tikitaka/naechinso/global/config/security/SecurityConfig.java index 361cc23..c92bd28 100644 --- a/src/main/java/com/tikitaka/naechinso/global/config/security/SecurityConfig.java +++ b/src/main/java/com/tikitaka/naechinso/global/config/security/SecurityConfig.java @@ -58,13 +58,10 @@ public SecurityFilterChain filterChain(HttpSecurity http) throws Exception { .requestMatchers(CorsUtils::isPreFlightRequest).permitAll() .antMatchers(SwaggerPatterns).permitAll() .antMatchers("/admin/**").hasAuthority("ROLE_ADMIN") - .antMatchers("/member/login").permitAll() .antMatchers("/member/join").permitAll() .antMatchers("/").permitAll() //health check .antMatchers("/sms/**").permitAll() - .antMatchers(HttpMethod.POST, "/recommend").permitAll() - .antMatchers("/recommend/**").permitAll() - .antMatchers("/recommend/request").permitAll() + .antMatchers(HttpMethod.GET, "/recommend/").permitAll() .anyRequest().authenticated() .and() .headers().frameOptions().disable(); diff --git a/src/main/java/com/tikitaka/naechinso/global/error/ErrorCode.java b/src/main/java/com/tikitaka/naechinso/global/error/ErrorCode.java index cc7d739..7a7843b 100644 --- a/src/main/java/com/tikitaka/naechinso/global/error/ErrorCode.java +++ b/src/main/java/com/tikitaka/naechinso/global/error/ErrorCode.java @@ -17,6 +17,8 @@ public enum ErrorCode { _UNAUTHORIZED(UNAUTHORIZED, "C002", "권한이 없습니다"), _METHOD_NOT_ALLOWED(METHOD_NOT_ALLOWED, "C003", "지원하지 않는 Http Method 입니다"), + CANNOT_CREATE_RECOMMEND(INTERNAL_SERVER_ERROR, "C004", "추천사 작성에 실패했습니다"), + CANNOT_CREATE_RECOMMEND_REQUEST(INTERNAL_SERVER_ERROR, "C005", "추천사 요청에 실패했습니다"), /* Auth 관련 오류 */ @@ -45,10 +47,11 @@ public enum ErrorCode { /* Recommend 관련 오류 */ RECOMMEND_NOT_FOUND(NOT_FOUND, "R000","해당 추천사 정보를 찾을 수 없습니다"), - RECOMMEND_ALREADY_EXIST(BAD_REQUEST, "R001","추천사 요청은 한 번만 보낼 수 있습니다"), + RECOMMEND_ALREADY_EXIST(BAD_REQUEST, "R001","추천사를 같은 사람에게 중복으로 보낼 수 없습니다"), CANNOT_RECOMMEND_MYSELF(BAD_REQUEST, "R002","자기 자신은 추천할 수 없습니다"), RECOMMEND_SENDER_ALREADY_EXIST(BAD_REQUEST, "R003","유저 추천사는 한 번만 작성할 수 있습니다"), RECOMMEND_RECEIVER_NOT_EXIST(BAD_REQUEST, "R004","추천 받을 사람이 존재하지 않습니다"), + RECOMMEND_REQUEST_ALREADY_EXIST(BAD_REQUEST, "R005","추천사 요청은 한 번만 보낼 수 있습니다"), /* Validation 오류 */ PARAMETER_NOT_VALID(BAD_REQUEST, "P000", "인자가 유효하지 않습니다"), From 17b54b47a22876ac06d6d7d7b755c3929a975357 Mon Sep 17 00:00:00 2001 From: gengminy Date: Fri, 7 Oct 2022 16:08:42 +0900 Subject: [PATCH 19/72] =?UTF-8?q?:hammer:=20fix(test):=20=ED=85=8C?= =?UTF-8?q?=EC=8A=A4=ED=8A=B8=20=EC=BD=94=EB=93=9C=20=EC=88=98=EC=A0=95=20?= =?UTF-8?q?#27?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../member/dto/MemberDetailJoinRequestDTO.java | 8 ++++---- .../unit/service/SmsCertificationServiceTest.java | 13 +++++++------ 2 files changed, 11 insertions(+), 10 deletions(-) diff --git a/src/main/java/com/tikitaka/naechinso/domain/member/dto/MemberDetailJoinRequestDTO.java b/src/main/java/com/tikitaka/naechinso/domain/member/dto/MemberDetailJoinRequestDTO.java index 20b4211..e5f3089 100644 --- a/src/main/java/com/tikitaka/naechinso/domain/member/dto/MemberDetailJoinRequestDTO.java +++ b/src/main/java/com/tikitaka/naechinso/domain/member/dto/MemberDetailJoinRequestDTO.java @@ -51,19 +51,19 @@ public class MemberDetailJoinRequestDTO { @ApiModelProperty(example = "ESTJ") @Length(max = 4, message = "올바른 MBTI 정보를 입력하세요") - private String mbti = ""; + private String mbti; @NotBlank(message = "성격 정보를 입력해야 합니다") private String personality; @NotBlank(message = "자기 소개를 입력해야 합니다") - private String introduce = ""; + private String introduce; @NotBlank(message = "취미 정보를 입력해야 합니다") - private String hobby = ""; + private String hobby; @NotBlank(message = "연애 스타일을 입력해야 합니다") - private String style = ""; + private String style; @NotBlank(message = "사진을 업로드해야 합니다") private String picture; diff --git a/src/test/java/com/tikitaka/naechinso/unit/service/SmsCertificationServiceTest.java b/src/test/java/com/tikitaka/naechinso/unit/service/SmsCertificationServiceTest.java index d1ab069..c328a43 100644 --- a/src/test/java/com/tikitaka/naechinso/unit/service/SmsCertificationServiceTest.java +++ b/src/test/java/com/tikitaka/naechinso/unit/service/SmsCertificationServiceTest.java @@ -25,6 +25,7 @@ import org.springframework.test.util.ReflectionTestUtils; import java.time.Duration; +import java.util.ArrayList; import java.util.Optional; import static org.assertj.core.api.Assertions.assertThat; @@ -85,7 +86,7 @@ void testVerifyCodeByNotSignedUpMember() { given(redisService.hasKey(key)).willReturn(true); given(redisService.getValues(key)).willReturn(verificationCode); given(memberRepository.findByPhone(receiver)).willReturn(Optional.empty()); - given(recommendService.existsByReceiverPhoneAndSenderNotNull(receiver)).willReturn(false); + given(recommendService.findAllRecommendReceivedListBasicByPhone(receiver)).willReturn(new ArrayList<>()); given(jwtTokenProvider.generateRegisterToken(new JwtDTO(receiver))).willReturn("rgT"); //when @@ -98,12 +99,12 @@ void testVerifyCodeByNotSignedUpMember() { verify(redisService, times(1)).hasKey(key); verify(redisService, times(1)).getValues(key); verify(memberRepository, times(1)).findByPhone(receiver); - verify(recommendService, times(1)).existsByReceiverPhoneAndSenderNotNull(receiver); + verify(recommendService, times(1)).findAllRecommendReceivedListBasicByPhone(receiver); verify(jwtTokenProvider, times(1)).generateRegisterToken(new JwtDTO(receiver)); assertThat(responseDTO.getAccessToken()).isNull(); assertThat(responseDTO.getRefreshToken()).isNull(); assertThat(responseDTO.getRegisterToken()).isEqualTo("rgT"); - assertThat(responseDTO.getRecommendReceived()).isFalse(); +// assertThat(responseDTO.getRecommendReceived()).isFalse(); } @DisplayName("가입한 회원의 Token 발급 테스트") @@ -124,7 +125,7 @@ void testVerifyCodeBySignedUpMember() { given(redisService.hasKey(key)).willReturn(true); given(redisService.getValues(key)).willReturn(verificationCode); given(memberRepository.findByPhone(receiver)).willReturn(Optional.of(member)); - given(recommendService.existsByReceiverPhoneAndSenderNotNull(receiver)).willReturn(false); + given(recommendService.findAllRecommendReceivedListBasicByPhone(receiver)).willReturn(new ArrayList<>()); given(jwtTokenProvider.generateToken(new JwtDTO(receiver, "ROLE_USER"))) .willReturn(TokenResponseDTO.builder().accessToken("aT").refreshToken("rfT").build()); @@ -138,13 +139,13 @@ void testVerifyCodeBySignedUpMember() { verify(redisService, times(1)).hasKey(key); verify(redisService, times(1)).getValues(key); verify(memberRepository, times(1)).findByPhone(receiver); - verify(recommendService, times(1)).existsByReceiverPhoneAndSenderNotNull(receiver); + verify(recommendService, times(1)).findAllRecommendReceivedListBasicByPhone(receiver); verify(jwtTokenProvider, times(1)).generateToken(new JwtDTO(receiver, "ROLE_USER")); assertThat(responseDTO.getAccessToken()).isEqualTo("aT"); assertThat(responseDTO.getRefreshToken()).isEqualTo("rfT"); assertThat(responseDTO.getRegisterToken()).isNull(); - assertThat(responseDTO.getRecommendReceived()).isFalse(); +// assertThat(responseDTO.getRecommendReceived()).isFalse(); } // From 5f840847205c8186a7ad699f46aaf1307eda6aab Mon Sep 17 00:00:00 2001 From: gengminy Date: Sat, 8 Oct 2022 16:04:54 +0900 Subject: [PATCH 20/72] =?UTF-8?q?:rocket:=20feat(s3):=20AWS=20S3=20?= =?UTF-8?q?=EC=97=B0=EA=B2=B0=20=EB=B0=8F=20=EA=B8=B0=EB=8A=A5=20=EC=B6=94?= =?UTF-8?q?=EA=B0=80=20#35?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- build.gradle | 3 + .../domain/member/MemberController.java | 40 +++++--- .../domain/member/MemberService.java | 12 +++ .../dto/MemberCommonJoinRequestDTO.java | 4 +- .../dto/MemberDetailJoinRequestDTO.java | 4 +- .../member/dto/MemberEduUpdateRequestDTO.java | 2 +- .../member/dto/MemberJobUpdateRequestDTO.java | 2 +- .../dto/MemberUpdateCommonRequestDTO.java | 4 +- .../domain/member/entity/Member.java | 16 +-- .../dto/RecommendBySenderRequestDTO.java | 98 +------------------ .../sms/SmsCertificationServiceImpl.java | 7 +- .../config/security/SecurityConfig.java | 1 + .../security/UserDetailServiceImpl.java | 2 - .../security/jwt/JwtAccessDeniedHandler.java | 16 ++- .../jwt/JwtAuthenticationEntryPoint.java | 4 + .../config/security/jwt/JwtTokenProvider.java | 10 +- .../naechinso/global/error/ErrorCode.java | 9 +- .../global/error/GlobalExceptionHandler.java | 68 +++++++++++-- .../naechinso/infra/image/AwsS3Config.java | 31 ++++++ .../infra/image/AwsS3Controller.java | 63 ++++++++++++ .../naechinso/infra/image/AwsS3Service.java | 21 ++++ .../infra/image/AwsS3ServiceImpl.java | 79 +++++++++++++++ .../infra/image/constant/AwsS3Directory.java | 24 +++++ .../{SmsService.java => NaverSmsService.java} | 2 +- ...viceImpl.java => NaverSmsServiceImpl.java} | 2 +- src/main/resources/application.yml | 1 + .../service/SmsCertificationServiceTest.java | 7 -- 27 files changed, 373 insertions(+), 159 deletions(-) create mode 100644 src/main/java/com/tikitaka/naechinso/infra/image/AwsS3Config.java create mode 100644 src/main/java/com/tikitaka/naechinso/infra/image/AwsS3Controller.java create mode 100644 src/main/java/com/tikitaka/naechinso/infra/image/AwsS3Service.java create mode 100644 src/main/java/com/tikitaka/naechinso/infra/image/AwsS3ServiceImpl.java create mode 100644 src/main/java/com/tikitaka/naechinso/infra/image/constant/AwsS3Directory.java rename src/main/java/com/tikitaka/naechinso/infra/sms/{SmsService.java => NaverSmsService.java} (73%) rename src/main/java/com/tikitaka/naechinso/infra/sms/{SmsServiceImpl.java => NaverSmsServiceImpl.java} (98%) diff --git a/build.gradle b/build.gradle index 835b3c1..4124161 100644 --- a/build.gradle +++ b/build.gradle @@ -37,6 +37,9 @@ dependencies { runtimeOnly 'org.postgresql:postgresql' implementation 'org.springframework.boot:spring-boot-starter-data-redis' + //AWS S3 + implementation 'io.awspring.cloud:spring-cloud-starter-aws:2.4.2' + //jwt implementation group: 'io.jsonwebtoken', name: 'jjwt', version: '0.9.1' diff --git a/src/main/java/com/tikitaka/naechinso/domain/member/MemberController.java b/src/main/java/com/tikitaka/naechinso/domain/member/MemberController.java index 9ff723a..39a1f47 100644 --- a/src/main/java/com/tikitaka/naechinso/domain/member/MemberController.java +++ b/src/main/java/com/tikitaka/naechinso/domain/member/MemberController.java @@ -3,9 +3,6 @@ import com.tikitaka.naechinso.domain.member.dto.*; import com.tikitaka.naechinso.domain.member.entity.Member; import com.tikitaka.naechinso.domain.recommend.RecommendService; -import com.tikitaka.naechinso.domain.recommend.dto.RecommendMemberAcceptRequestDTO; -import com.tikitaka.naechinso.domain.recommend.dto.RecommendMemberAcceptAndUpdateRequestDTO; -import com.tikitaka.naechinso.domain.recommend.dto.RecommendResponseDTO; import com.tikitaka.naechinso.global.annotation.AuthMember; import com.tikitaka.naechinso.global.config.CommonApiResponse; import com.tikitaka.naechinso.global.config.security.jwt.JwtTokenProvider; @@ -30,6 +27,7 @@ public class MemberController { private final JwtTokenProvider jwtTokenService; + @GetMapping @ApiOperation(value = "유저 자신의 모든 정보를 가져온다 (AccessToken)") public CommonApiResponse getMyInformation( @@ -38,7 +36,6 @@ public CommonApiResponse getMyInformation( return CommonApiResponse.of(MemberCommonResponseDTO.of(member)); } - @GetMapping("/detail") @ApiOperation(value = "회원가입 세부 정보를 가져온다 (AccessToken 필요)") public CommonApiResponse getMemberDetail( @@ -48,7 +45,6 @@ public CommonApiResponse getMemberDetail( return CommonApiResponse.of(res); } - @PostMapping("/join") @ApiOperation(value = "유저를 공통 정보로 가입시킨다 (RegisterToken)") public CommonApiResponse joinCommonMember( @@ -59,6 +55,16 @@ public CommonApiResponse joinCommonMember( return CommonApiResponse.of(memberService.joinCommonMember(phone, dto)); } + @PostMapping("/join/detail") + @ApiOperation(value = "회원가입 세부 정보를 입력하여 최종 가입시킨다 (AccessToken)") + public CommonApiResponse setMemberDetail( + @Valid @RequestBody MemberDetailJoinRequestDTO dto, + @ApiIgnore @AuthMember Member member + ) { + final MemberDetailResponseDTO res = memberService.createDetail(member, dto); + return CommonApiResponse.of(res); + } + @PatchMapping("/common") @ApiOperation(value = "유저를 공통 정보를 수정한다 (AccessToken)") public CommonApiResponse updateCommonMember( @@ -86,19 +92,23 @@ public CommonApiResponse setMemberJob( return CommonApiResponse.of(memberService.updateEdu(member, dto)); } +// @PostMapping(value = "/image", consumes = {MediaType.MULTIPART_FORM_DATA_VALUE}) +// @ApiOperation(value = "프로필 이미지를 업로드하고 이미지 URL 을 가져온다 (AccessToken)") +// public CommonApiResponse> updateProfileImage( +// @Parameter( +// description = "업로드 파일 리스트", +// content = @Content(mediaType = MediaType.APPLICATION_OCTET_STREAM_VALUE), +// required = true +// ) +// @RequestPart List multipartFile, +// @ApiIgnore @AuthMember Member member +// ) { +//// awsS3Service.uploadImage(multipartFile, dirName); +// return CommonApiResponse.of(null); +// } - @PostMapping("/join/detail") - @ApiOperation(value = "회원가입 세부 정보를 입력하여 최종 가입시킨다 (AccessToken)") - public CommonApiResponse setMemberDetail( - @Valid @RequestBody MemberDetailJoinRequestDTO dto, - @ApiIgnore @AuthMember Member member - ) { - final MemberDetailResponseDTO res = memberService.createDetail(member, dto); - return CommonApiResponse.of(res); - } - //페이징 처리 추가할 예정 @GetMapping("/find") @ApiOperation(value = "[Admin]현재 가입한 모든 유저를 불러온다 (AccessToken)") diff --git a/src/main/java/com/tikitaka/naechinso/domain/member/MemberService.java b/src/main/java/com/tikitaka/naechinso/domain/member/MemberService.java index 056da21..6b2ca5c 100644 --- a/src/main/java/com/tikitaka/naechinso/domain/member/MemberService.java +++ b/src/main/java/com/tikitaka/naechinso/domain/member/MemberService.java @@ -17,6 +17,7 @@ import org.springframework.security.core.context.SecurityContextHolder; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; +import org.springframework.web.multipart.MultipartFile; import java.util.List; import java.util.Optional; @@ -137,6 +138,17 @@ public MemberCommonResponseDTO updateEdu(Member authMember, MemberEduUpdateReque return MemberCommonResponseDTO.of(member); } + /** + * MemberDetail 의 프로필 이미지를 업로드 한다 + * */ +// public List updateProfileImage(Member authMember, List multipartFile){ +// //영속성 유지를 위한 fetch +// Member member = findByMember(authMember); +// +// memberRepository.save(member); +// return MemberCommonResponseDTO.of(member); +// } + public void validateToken(Member authMember) { if (authMember == null) { diff --git a/src/main/java/com/tikitaka/naechinso/domain/member/dto/MemberCommonJoinRequestDTO.java b/src/main/java/com/tikitaka/naechinso/domain/member/dto/MemberCommonJoinRequestDTO.java index d40136c..8db3e5e 100644 --- a/src/main/java/com/tikitaka/naechinso/domain/member/dto/MemberCommonJoinRequestDTO.java +++ b/src/main/java/com/tikitaka/naechinso/domain/member/dto/MemberCommonJoinRequestDTO.java @@ -27,8 +27,8 @@ public class MemberCommonJoinRequestDTO { private Gender gender; @ApiModelProperty(example = "25") - @Min(value = 25, message = "25-33세까지만 가입 가능합니다") - @Max(value = 33, message = "25-33세까지만 가입 가능합니다") + @Min(value = 25, message = "25-35세까지만 가입 가능합니다") + @Max(value = 35, message = "25-35세까지만 가입 가능합니다") private int age; @NotNull(message = "서비스 이용약관 동의가 필요합니다") diff --git a/src/main/java/com/tikitaka/naechinso/domain/member/dto/MemberDetailJoinRequestDTO.java b/src/main/java/com/tikitaka/naechinso/domain/member/dto/MemberDetailJoinRequestDTO.java index e5f3089..e044e94 100644 --- a/src/main/java/com/tikitaka/naechinso/domain/member/dto/MemberDetailJoinRequestDTO.java +++ b/src/main/java/com/tikitaka/naechinso/domain/member/dto/MemberDetailJoinRequestDTO.java @@ -28,8 +28,8 @@ public class MemberDetailJoinRequestDTO { private Gender gender; @ApiModelProperty(example = "25") - @Min(value = 25, message = "25-33세까지만 가입 가능합니다") - @Max(value = 33, message = "25-33세까지만 가입 가능합니다") + @Min(value = 25, message = "25-35세까지만 가입 가능합니다") + @Max(value = 35, message = "25-35세까지만 가입 가능합니다") private int age; @ApiModelProperty(example = "180") diff --git a/src/main/java/com/tikitaka/naechinso/domain/member/dto/MemberEduUpdateRequestDTO.java b/src/main/java/com/tikitaka/naechinso/domain/member/dto/MemberEduUpdateRequestDTO.java index 08ab20d..107a32f 100644 --- a/src/main/java/com/tikitaka/naechinso/domain/member/dto/MemberEduUpdateRequestDTO.java +++ b/src/main/java/com/tikitaka/naechinso/domain/member/dto/MemberEduUpdateRequestDTO.java @@ -29,5 +29,5 @@ public class MemberEduUpdateRequestDTO { @ApiModelProperty(example = "인증 사진 링크") @NotBlank(message = "인증 사진을 업로드 해주세요") - private String eduPicture; + private String eduImage; } diff --git a/src/main/java/com/tikitaka/naechinso/domain/member/dto/MemberJobUpdateRequestDTO.java b/src/main/java/com/tikitaka/naechinso/domain/member/dto/MemberJobUpdateRequestDTO.java index 7990630..fabe08e 100644 --- a/src/main/java/com/tikitaka/naechinso/domain/member/dto/MemberJobUpdateRequestDTO.java +++ b/src/main/java/com/tikitaka/naechinso/domain/member/dto/MemberJobUpdateRequestDTO.java @@ -29,5 +29,5 @@ public class MemberJobUpdateRequestDTO { @ApiModelProperty(example = "인증 사진 링크") @NotBlank(message = "인증 사진을 업로드 해주세요") - private String jobPicture; + private String jobImage; } diff --git a/src/main/java/com/tikitaka/naechinso/domain/member/dto/MemberUpdateCommonRequestDTO.java b/src/main/java/com/tikitaka/naechinso/domain/member/dto/MemberUpdateCommonRequestDTO.java index 40fef9d..5ea3810 100644 --- a/src/main/java/com/tikitaka/naechinso/domain/member/dto/MemberUpdateCommonRequestDTO.java +++ b/src/main/java/com/tikitaka/naechinso/domain/member/dto/MemberUpdateCommonRequestDTO.java @@ -24,7 +24,7 @@ public class MemberUpdateCommonRequestDTO { private Gender gender; @ApiModelProperty(example = "25") - @Min(value = 25, message = "25-33세까지만 가입 가능합니다") - @Max(value = 33, message = "25-33세까지만 가입 가능합니다") + @Min(value = 25, message = "25-35세까지만 가입 가능합니다") + @Max(value = 35, message = "25-35세까지만 가입 가능합니다") private int age; } diff --git a/src/main/java/com/tikitaka/naechinso/domain/member/entity/Member.java b/src/main/java/com/tikitaka/naechinso/domain/member/entity/Member.java index 68ceb7d..5b4d851 100644 --- a/src/main/java/com/tikitaka/naechinso/domain/member/entity/Member.java +++ b/src/main/java/com/tikitaka/naechinso/domain/member/entity/Member.java @@ -80,23 +80,23 @@ public class Member extends BaseEntity { @Column(name = "mem_job_location") private String jobLocation; - @Column(name = "mem_job_picture") - private String jobPicture; + @Column(name = "mem_job_image") + private String jobImage; @Column(name = "mem_job_accepted") private String jobAccepted; - @Column(name = "mem_school") + @Column(name = "mem_edu_school") private String eduName; - @Column(name = "mem_major") + @Column(name = "mem_edu_major") private String eduMajor; @Column(name = "mem_edu_level") private String eduLevel; - @Column(name = "mem_edu_picture") - private String eduPicture; + @Column(name = "mem_edu_image") + private String eduImage; @Column(name = "mem_edu_accepted") private String eduAccepted; @@ -135,14 +135,14 @@ public void updateJob(MemberJobUpdateRequestDTO requestDTO) { this.jobName = requestDTO.getJobName(); this.jobLocation = requestDTO.getJobLocation(); this.jobPart = requestDTO.getJobPart(); - this.jobPicture = requestDTO.getJobPicture(); + this.jobImage = requestDTO.getJobImage(); } public void updateEdu(MemberEduUpdateRequestDTO requestDTO) { this.eduName = requestDTO.getEduName(); this.eduMajor = requestDTO.getEduMajor(); this.eduLevel = requestDTO.getEduLevel(); - this.eduPicture = requestDTO.getEduPicture(); + this.eduImage = requestDTO.getEduImage(); } public void updateCommon(MemberUpdateCommonRequestDTO dto) { diff --git a/src/main/java/com/tikitaka/naechinso/domain/recommend/dto/RecommendBySenderRequestDTO.java b/src/main/java/com/tikitaka/naechinso/domain/recommend/dto/RecommendBySenderRequestDTO.java index 54bfb89..d097e26 100644 --- a/src/main/java/com/tikitaka/naechinso/domain/recommend/dto/RecommendBySenderRequestDTO.java +++ b/src/main/java/com/tikitaka/naechinso/domain/recommend/dto/RecommendBySenderRequestDTO.java @@ -1,9 +1,6 @@ package com.tikitaka.naechinso.domain.recommend.dto; import com.tikitaka.naechinso.domain.member.constant.Gender; -import com.tikitaka.naechinso.domain.member.dto.MemberEduUpdateRequestDTO; -import com.tikitaka.naechinso.domain.member.dto.MemberJobUpdateRequestDTO; -import com.tikitaka.naechinso.domain.member.entity.Member; import com.tikitaka.naechinso.global.annotation.Enum; import io.swagger.annotations.ApiModelProperty; import lombok.*; @@ -19,45 +16,6 @@ @Builder @ToString public class RecommendBySenderRequestDTO { -// @ApiModelProperty(example = "닉") -// @NotBlank(message = "이름을 입력해주세요") -// private String name; -// -// @ApiModelProperty(example = "M") -// @Enum(enumClass = Gender.class, message = "성별 입력이 올바르지 않습니다. M 또는 W가 필요합니다") -// private Gender gender; -// -// @ApiModelProperty(example = "25") -// @Min(value = 25, message = "25-33세까지만 가입 가능합니다") -// @Max(value = 33, message = "25-33세까지만 가입 가능합니다") -// private int age; -// -// @NotNull(message = "서비스 이용약관 동의가 필요합니다") -// @AssertTrue(message = "서비스 이용약관 동의가 필요합니다") -// private boolean acceptsService; -// -// @NotNull(message = "개인정보 이용 동의가 필요합니다") -// @AssertTrue(message = "개인정보 이용 동의가 필요합니다") -// private boolean acceptsInfo; -// -// @NotNull(message = "종교 정보 제공 동의가 필요합니다") -// @AssertTrue(message = "종교 정보 제공 동의가 필요합니다") -// private boolean acceptsReligion; -// -// @NotNull(message = "위치 정보 제공 동의 여부가 필요합니다") -// private boolean acceptsLocation; -// -// @NotNull(message = "마케팅 동의 여부가 필요합니다") -// private boolean acceptsMarketing; -// -// private MemberEduUpdateRequestDTO edu; -// -// private MemberJobUpdateRequestDTO job; -// -// -// - - @ApiModelProperty(example = "01099999999") @NotBlank(message = "친구의 전화번호를 입력해주세요") @Pattern(regexp = "[0-9]{10,11}", message = "하이픈 없는 10~11자리 숫자를 입력해주세요") @@ -72,8 +30,8 @@ public class RecommendBySenderRequestDTO { private Gender gender; @ApiModelProperty(example = "25") - @Min(value = 25, message = "25-33세까지만 추천 및 가입 가능합니다") - @Max(value = 33, message = "25-33세까지만 추천 및 가입 가능합니다") + @Min(value = 25, message = "25-35세까지만 추천 및 가입 가능합니다") + @Max(value = 35, message = "25-35세까지만 추천 및 가입 가능합니다") private int age; @ApiModelProperty(example = "CMC 에서") @@ -91,56 +49,4 @@ public class RecommendBySenderRequestDTO { @ApiModelProperty(example = "1년") @NotBlank(message = "만난 기간을 입력해주세요") private String period; -// -// public Member toSender(String phone){ -// Member.MemberBuilder builder = Member.builder(); -// if (this.job != null) { -// builder.jobName(this.job.getJobName()) -// .jobPart(this.job.getJobPart()) -// .jobLocation(this.job.getJobLocation()) -// .jobPicture(this.job.getJobPicture()); -// } -// -// if (this.edu != null) { -// builder.eduName(this.edu.getEduName()) -// .eduMajor(this.edu.getEduMajor()) -// .eduLevel(this.edu.getEduMajor()) -// .eduPicture(this.edu.getEduPicture()); -// } -// -// return builder -// .phone(phone) -// .name(this.name) -// .gender(this.gender) -// .age(this.age) -// .acceptsService(this.acceptsService) -// .acceptsInfo(this.acceptsInfo) -// .acceptsReligion(this.acceptsReligion) -// .acceptsLocation(this.acceptsLocation) -// .acceptsMarketing(this.acceptsMarketing) -// .build(); -// } - - public Member toReceiver(String phone){ -// if (job != null) { -// builder.jobName(this.job.getJobName()) -// .jobPart(this.job.getJobPart()) -// .jobLocation(this.job.getJobLocation()) -// .jobPicture(this.job.getJobPicture()); -// } -// -// if (edu != null) { -// builder.eduName(this.edu.getEduName()) -// .eduMajor(this.edu.getEduMajor()) -// .eduLevel(this.edu.getEduMajor()) -// .eduPicture(this.edu.getEduPicture()); -// } - - return Member.builder() - .phone(phone) - .name(this.name) - .gender(this.gender) - .age(this.age) - .build(); - } } diff --git a/src/main/java/com/tikitaka/naechinso/domain/sms/SmsCertificationServiceImpl.java b/src/main/java/com/tikitaka/naechinso/domain/sms/SmsCertificationServiceImpl.java index 4632df5..323fba3 100644 --- a/src/main/java/com/tikitaka/naechinso/domain/sms/SmsCertificationServiceImpl.java +++ b/src/main/java/com/tikitaka/naechinso/domain/sms/SmsCertificationServiceImpl.java @@ -4,14 +4,13 @@ import com.tikitaka.naechinso.domain.member.entity.Member; import com.tikitaka.naechinso.domain.recommend.RecommendService; import com.tikitaka.naechinso.domain.recommend.dto.RecommendReceiverDTO; -import com.tikitaka.naechinso.domain.recommend.dto.RecommendResponseDTO; import com.tikitaka.naechinso.domain.sms.dto.SmsCertificationSuccessResponseDTO; import com.tikitaka.naechinso.global.common.response.TokenResponseDTO; import com.tikitaka.naechinso.global.config.security.dto.JwtDTO; import com.tikitaka.naechinso.global.config.security.jwt.JwtTokenProvider; import com.tikitaka.naechinso.global.error.ErrorCode; import com.tikitaka.naechinso.global.error.exception.InternalServerException; -import com.tikitaka.naechinso.infra.sms.SmsService; +import com.tikitaka.naechinso.infra.sms.NaverSmsService; import com.tikitaka.naechinso.domain.sms.dto.SmsCertificationRequestDTO; import com.tikitaka.naechinso.global.error.exception.BadRequestException; import com.tikitaka.naechinso.global.error.exception.UnauthorizedException; @@ -31,7 +30,7 @@ @RequiredArgsConstructor public class SmsCertificationServiceImpl implements SmsCertificationService { - private final SmsService smsService; + private final NaverSmsService naverSmsService; private final RedisService redisService; private final JwtTokenProvider jwtTokenProvider; private final MemberRepository memberRepository; @@ -66,7 +65,7 @@ public String sendVerificationMessage(String to) { //[prod] 실 배포 환경에서는 문자를 전송합니다 try { //네이버 sms 메세지 dto - if (smsService.sendMessage(to, generateMessageWithCode(verificationCode))) { + if (naverSmsService.sendMessage(to, generateMessageWithCode(verificationCode))) { //전송 성공하면 redis 에 3분 제한의 인증번호 토큰 저장 redisService.setValues(VERIFICATION_PREFIX + to, verificationCode, verificationTimeLimit); return "메세지 전송 성공"; diff --git a/src/main/java/com/tikitaka/naechinso/global/config/security/SecurityConfig.java b/src/main/java/com/tikitaka/naechinso/global/config/security/SecurityConfig.java index c92bd28..8bff31a 100644 --- a/src/main/java/com/tikitaka/naechinso/global/config/security/SecurityConfig.java +++ b/src/main/java/com/tikitaka/naechinso/global/config/security/SecurityConfig.java @@ -57,6 +57,7 @@ public SecurityFilterChain filterChain(HttpSecurity http) throws Exception { .authorizeRequests() .requestMatchers(CorsUtils::isPreFlightRequest).permitAll() .antMatchers(SwaggerPatterns).permitAll() + .antMatchers(HttpMethod.DELETE,"/s3/image").hasAuthority("ROLE_ADMIN") .antMatchers("/admin/**").hasAuthority("ROLE_ADMIN") .antMatchers("/member/join").permitAll() .antMatchers("/").permitAll() //health check diff --git a/src/main/java/com/tikitaka/naechinso/global/config/security/UserDetailServiceImpl.java b/src/main/java/com/tikitaka/naechinso/global/config/security/UserDetailServiceImpl.java index 3d03d24..a731e70 100644 --- a/src/main/java/com/tikitaka/naechinso/global/config/security/UserDetailServiceImpl.java +++ b/src/main/java/com/tikitaka/naechinso/global/config/security/UserDetailServiceImpl.java @@ -12,9 +12,7 @@ @RequiredArgsConstructor @Service public class UserDetailServiceImpl implements UserDetailsService { - private final MemberRepository memberRepository; - @Override public UserDetails loadUserByUsername(String phone) throws UsernameNotFoundException { Member member = memberRepository.findByPhone(phone) diff --git a/src/main/java/com/tikitaka/naechinso/global/config/security/jwt/JwtAccessDeniedHandler.java b/src/main/java/com/tikitaka/naechinso/global/config/security/jwt/JwtAccessDeniedHandler.java index 71bc23a..7b673c3 100644 --- a/src/main/java/com/tikitaka/naechinso/global/config/security/jwt/JwtAccessDeniedHandler.java +++ b/src/main/java/com/tikitaka/naechinso/global/config/security/jwt/JwtAccessDeniedHandler.java @@ -1,6 +1,7 @@ package com.tikitaka.naechinso.global.config.security.jwt; import com.tikitaka.naechinso.global.error.ErrorCode; +import com.tikitaka.naechinso.global.error.ErrorResponse; import com.tikitaka.naechinso.global.error.exception.ForbiddenException; import lombok.extern.slf4j.Slf4j; import org.springframework.security.access.AccessDeniedException; @@ -21,8 +22,19 @@ public void handle( HttpServletRequest request, HttpServletResponse response, AccessDeniedException accessDeniedException - ) throws IOException, ServletException { + ) throws IOException { // 필요한 권한이 없이 접근하려 할때 403 - throw new ForbiddenException(ErrorCode.FORBIDDEN_USER); + ErrorCode errorCode = ErrorCode.FORBIDDEN_USER; + setResponse(response, errorCode); } + + /** + * 스프링 시큐티리 예외 커스텀을 위한 함수 + */ + private void setResponse(HttpServletResponse response, ErrorCode errorCode) throws IOException { + response.setContentType("application/json;charset=UTF-8"); + response.setStatus(HttpServletResponse.SC_UNAUTHORIZED); + response.getWriter().print(ErrorResponse.jsonOf(errorCode)); + } + } \ No newline at end of file diff --git a/src/main/java/com/tikitaka/naechinso/global/config/security/jwt/JwtAuthenticationEntryPoint.java b/src/main/java/com/tikitaka/naechinso/global/config/security/jwt/JwtAuthenticationEntryPoint.java index e54eec2..978bbb9 100644 --- a/src/main/java/com/tikitaka/naechinso/global/config/security/jwt/JwtAuthenticationEntryPoint.java +++ b/src/main/java/com/tikitaka/naechinso/global/config/security/jwt/JwtAuthenticationEntryPoint.java @@ -39,6 +39,10 @@ public void commence( else if(exception.equals(ErrorCode.INVALID_AUTH_TOKEN.getCode())) { setResponse(response, ErrorCode.INVALID_AUTH_TOKEN); } + //DB에 정보가 없는 토큰을 사용했울 때 + else if(exception.equals(ErrorCode.INVALID_USER_TOKEN.getCode())) { + setResponse(response, ErrorCode.INVALID_USER_TOKEN); + } //잘못된 서명 else if(exception.equals(ErrorCode.INVALID_SIGNATURE.getCode())) { setResponse(response, ErrorCode.INVALID_SIGNATURE); diff --git a/src/main/java/com/tikitaka/naechinso/global/config/security/jwt/JwtTokenProvider.java b/src/main/java/com/tikitaka/naechinso/global/config/security/jwt/JwtTokenProvider.java index 2c4b60b..9606600 100644 --- a/src/main/java/com/tikitaka/naechinso/global/config/security/jwt/JwtTokenProvider.java +++ b/src/main/java/com/tikitaka/naechinso/global/config/security/jwt/JwtTokenProvider.java @@ -129,9 +129,13 @@ public Authentication getAuthentication(HttpServletRequest request, String acces throw new UnauthorizedException(ErrorCode.INVALID_AUTH_TOKEN); } - UserDetails principal = loginService.loadUserByUsername(claims.getSubject()); - - return new UsernamePasswordAuthenticationToken(principal, "", principal.getAuthorities()); + try { + UserDetails principal = loginService.loadUserByUsername(claims.getSubject()); + return new UsernamePasswordAuthenticationToken(principal, "", principal.getAuthorities()); + } catch (Exception e) { + request.setAttribute("exception", ErrorCode.INVALID_USER_TOKEN.getCode()); + throw e; + } } diff --git a/src/main/java/com/tikitaka/naechinso/global/error/ErrorCode.java b/src/main/java/com/tikitaka/naechinso/global/error/ErrorCode.java index 7a7843b..f063d73 100644 --- a/src/main/java/com/tikitaka/naechinso/global/error/ErrorCode.java +++ b/src/main/java/com/tikitaka/naechinso/global/error/ErrorCode.java @@ -17,9 +17,13 @@ public enum ErrorCode { _UNAUTHORIZED(UNAUTHORIZED, "C002", "권한이 없습니다"), _METHOD_NOT_ALLOWED(METHOD_NOT_ALLOWED, "C003", "지원하지 않는 Http Method 입니다"), - CANNOT_CREATE_RECOMMEND(INTERNAL_SERVER_ERROR, "C004", "추천사 작성에 실패했습니다"), - CANNOT_CREATE_RECOMMEND_REQUEST(INTERNAL_SERVER_ERROR, "C005", "추천사 요청에 실패했습니다"), + _UNSUPPORTED_MEDIA_TYPE(UNSUPPORTED_MEDIA_TYPE, "C004", "지원하지 않는 Http Media Type 입니다"), + _INVALID_REQUEST_PARAMETER(BAD_REQUEST, "C005", "유효하지 않은 Request Parameter 입니다"), + CANNOT_CREATE_RECOMMEND(INTERNAL_SERVER_ERROR, "C006", "추천사 작성에 실패했습니다"), + CANNOT_CREATE_RECOMMEND_REQUEST(INTERNAL_SERVER_ERROR, "C007", "추천사 요청에 실패했습니다"), + NOT_MULTIPART_HEADER(BAD_REQUEST, "C008", "Multipart 헤더가 아닙니다"), + AMAZON_ACCESS_DENIED(FORBIDDEN, "C009", "Amazon S3 접근이 거부되었습니다"), /* Auth 관련 오류 */ NO_TOKEN(UNAUTHORIZED, "AUTH000", "토큰이 존재하지 않습니다"), @@ -34,6 +38,7 @@ public enum ErrorCode { INVALID_SIGNATURE(UNAUTHORIZED, "AUTH009", "잘못된 JWT 서명입니다"), MISMATCH_VERIFICATION_CODE(UNAUTHORIZED, "AUTH010", "인증번호가 일치하지 않습니다"), EXPIRED_VERIFICATION_CODE(UNAUTHORIZED, "AUTH011", "인증번호가 만료되었습니다"), + INVALID_USER_TOKEN(UNAUTHORIZED, "AUTH012", "서버에 토큰과 일치하는 정보가 없습니다"), LOGIN_FAILED(UNAUTHORIZED, "AUTH012", "로그인에 실패했습니다"), diff --git a/src/main/java/com/tikitaka/naechinso/global/error/GlobalExceptionHandler.java b/src/main/java/com/tikitaka/naechinso/global/error/GlobalExceptionHandler.java index 24f24fd..dc27c7f 100644 --- a/src/main/java/com/tikitaka/naechinso/global/error/GlobalExceptionHandler.java +++ b/src/main/java/com/tikitaka/naechinso/global/error/GlobalExceptionHandler.java @@ -1,5 +1,6 @@ package com.tikitaka.naechinso.global.error; +import com.amazonaws.services.s3.model.AmazonS3Exception; import com.tikitaka.naechinso.global.error.exception.BusinessException; import lombok.extern.slf4j.Slf4j; import org.springframework.http.HttpStatus; @@ -7,10 +8,14 @@ import org.springframework.security.access.AccessDeniedException; import org.springframework.security.authentication.BadCredentialsException; import org.springframework.security.core.AuthenticationException; +import org.springframework.web.HttpMediaTypeNotSupportedException; import org.springframework.web.HttpRequestMethodNotSupportedException; import org.springframework.web.bind.MethodArgumentNotValidException; +import org.springframework.web.bind.MissingServletRequestParameterException; import org.springframework.web.bind.annotation.ExceptionHandler; import org.springframework.web.bind.annotation.RestControllerAdvice; +import org.springframework.web.method.annotation.MethodArgumentTypeMismatchException; +import org.springframework.web.multipart.MultipartException; import java.util.Arrays; @@ -42,16 +47,26 @@ protected ResponseEntity handleMethodArgumentNotValidException(Me } -// /** -// * enum type 일치하지 않아 binding 못할 경우 발생 -// * 주로 @RequestParam enum으로 binding 못했을 경우 발생 -// */ -// @ExceptionHandler(MethodArgumentTypeMismatchException.class) -// protected ResponseEntity handleMethodArgumentTypeMismatchException(MethodArgumentTypeMismatchException e) { -// log.error("handleMethodArgumentTypeMismatchException", e); -// final ErrorResponse response = ErrorResponse.of(e); -// return new ResponseEntity<>(response, HttpStatus.BAD_REQUEST); -// } + /** + * enum type 일치하지 않아 binding 못할 경우 발생 + * 주로 @RequestParam enum으로 binding 못했을 경우 발생 + */ + @ExceptionHandler(MethodArgumentTypeMismatchException.class) + protected ResponseEntity handleMethodArgumentTypeMismatchException(MethodArgumentTypeMismatchException e) { + log.error("handleMethodArgumentTypeMismatchException", e); + final ErrorResponse response = ErrorResponse.of(ErrorCode._INVALID_REQUEST_PARAMETER); + return new ResponseEntity<>(response, HttpStatus.BAD_REQUEST); + } + /** + * Request Param 타입이 일치하지 않을 때 발생 + */ + @ExceptionHandler(MissingServletRequestParameterException.class) + protected ResponseEntity handleMissingServletRequestParameterException(MissingServletRequestParameterException e) { + log.error("handleMissingServletRequestParameterException", e); + final ErrorResponse response = ErrorResponse.of(ErrorCode._INVALID_REQUEST_PARAMETER); + return new ResponseEntity<>(response, HttpStatus.BAD_REQUEST); + } + /** * 지원하지 않은 HTTP method 호출 할 경우 발생 @@ -63,6 +78,16 @@ protected ResponseEntity handleHttpRequestMethodNotSupportedExcep return new ResponseEntity<>(response, HttpStatus.METHOD_NOT_ALLOWED); } + /** + * 지원하지 않은 HTTP Media Type 호출 할 경우 발생 + */ + @ExceptionHandler(HttpMediaTypeNotSupportedException.class) + protected ResponseEntity handleHttpMediaTypeNotSupportedException(HttpMediaTypeNotSupportedException e) { + log.error("handleHttpMediaTypeNotSupportedException", e); + final ErrorResponse response = ErrorResponse.of(ErrorCode._UNSUPPORTED_MEDIA_TYPE); + return new ResponseEntity<>(response, HttpStatus.UNSUPPORTED_MEDIA_TYPE); + } + /** * Authentication 객체가 필요한 권한을 보유하지 않은 경우 발생합 */ @@ -83,6 +108,29 @@ protected ResponseEntity handleBadCredentialsException(BadCredent return new ResponseEntity<>(response, HttpStatus.UNAUTHORIZED); } + /** + * 파일 업로드 시 멀티파트 헤더를 설정하지 않았을때 에러 + */ + @ExceptionHandler({MultipartException.class}) + protected ResponseEntity handleMultipartException(MultipartException e) { + log.error("handleMultipartException", e); + final ErrorResponse response = ErrorResponse.of(ErrorCode.NOT_MULTIPART_HEADER); + return new ResponseEntity<>(response, HttpStatus.BAD_REQUEST); + } + + /** + * 아마존 S3 접근 오류 + */ + @ExceptionHandler({AmazonS3Exception.class}) + protected ResponseEntity handleMultipartException(AmazonS3Exception e) { + log.error("handleAmazonS3Exception", e); + final ErrorResponse response = ErrorResponse.of(ErrorCode.AMAZON_ACCESS_DENIED); + return new ResponseEntity<>(response, HttpStatus.FORBIDDEN); + } + + + + @ExceptionHandler protected ResponseEntity handleAllException(Exception e) { log.error("Exception : {}", e); diff --git a/src/main/java/com/tikitaka/naechinso/infra/image/AwsS3Config.java b/src/main/java/com/tikitaka/naechinso/infra/image/AwsS3Config.java new file mode 100644 index 0000000..a16242d --- /dev/null +++ b/src/main/java/com/tikitaka/naechinso/infra/image/AwsS3Config.java @@ -0,0 +1,31 @@ +package com.tikitaka.naechinso.infra.image; + +import com.amazonaws.auth.AWSStaticCredentialsProvider; +import com.amazonaws.auth.BasicAWSCredentials; +import com.amazonaws.services.s3.AmazonS3Client; +import com.amazonaws.services.s3.AmazonS3ClientBuilder; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; + +@Configuration +public class AwsS3Config { + + @Value("${cloud.aws.credentials.access-key}") + private String accessKey; + + @Value("${cloud.aws.credentials.secret-key}") + private String secretKey; + + @Value("${cloud.aws.region.static}") + private String region; + + @Bean + public AmazonS3Client amazonS3Client() { + BasicAWSCredentials awsCredentials = new BasicAWSCredentials(accessKey, secretKey); + return (AmazonS3Client) AmazonS3ClientBuilder.standard() + .withRegion(region) + .withCredentials(new AWSStaticCredentialsProvider(awsCredentials)) + .build(); + } +} diff --git a/src/main/java/com/tikitaka/naechinso/infra/image/AwsS3Controller.java b/src/main/java/com/tikitaka/naechinso/infra/image/AwsS3Controller.java new file mode 100644 index 0000000..dfba389 --- /dev/null +++ b/src/main/java/com/tikitaka/naechinso/infra/image/AwsS3Controller.java @@ -0,0 +1,63 @@ +package com.tikitaka.naechinso.infra.image; + +import com.tikitaka.naechinso.domain.member.entity.Member; +import com.tikitaka.naechinso.global.annotation.AuthMember; +import com.tikitaka.naechinso.global.config.CommonApiResponse; +import com.tikitaka.naechinso.infra.image.constant.AwsS3Directory; +import io.swagger.annotations.ApiOperation; +import io.swagger.annotations.ApiParam; +import io.swagger.v3.oas.annotations.Parameter; +import io.swagger.v3.oas.annotations.media.Content; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.springframework.http.MediaType; +import org.springframework.web.bind.annotation.*; +import org.springframework.web.multipart.MultipartFile; +import springfox.documentation.annotations.ApiIgnore; + +import java.util.List; + +/** + * Amazon S3 이미지 업로드 및 삭제 기능을 담당합니다 + * */ +@Slf4j +@RestController +@RequiredArgsConstructor +@RequestMapping("/s3") +public class AwsS3Controller { + + private final AwsS3ServiceImpl awsS3ServiceImpl; + + /** + * Amazon S3에 이미지 업로드 + * @return 성공 시 200 / 함께 업로드 된 파일의 파일명 리스트 반영 + */ + @ApiOperation(value = "Amazon S3에 이미지를 업로드한다", notes = "Amazon S3에 이미지 업로드 ") + @PostMapping(value = "/image", consumes = {MediaType.MULTIPART_FORM_DATA_VALUE}) + public CommonApiResponse> uploadImage( + @Parameter( + description = "업로드 할 파일 리스트", + content = @Content(mediaType = MediaType.APPLICATION_OCTET_STREAM_VALUE) // Won't work without OCTET_STREAM as the mediaType. + ) + @RequestPart List multipartFiles, + @RequestParam AwsS3Directory dirName, + @ApiIgnore @AuthMember Member member + ) { + return CommonApiResponse.of(awsS3ServiceImpl.uploadImage(multipartFiles, dirName.name())); + } + + /** + * Amazon S3에 이미지 업로드 된 파일을 삭제 + * @return 성공 시 200 Success + */ + @ApiOperation(value = "[Admin] Amazon S3에 업로드 된 파일을 삭제한다", notes = "Amazon S3에 업로드된 이미지 삭제") + @DeleteMapping("/image") + public CommonApiResponse deleteImage( + @ApiParam(value="img 파일 하나 삭제", required = true) + @RequestParam String fileName + ) { + awsS3ServiceImpl.deleteImage(fileName); + return CommonApiResponse.of(null); + } + +} \ No newline at end of file diff --git a/src/main/java/com/tikitaka/naechinso/infra/image/AwsS3Service.java b/src/main/java/com/tikitaka/naechinso/infra/image/AwsS3Service.java new file mode 100644 index 0000000..d4915f0 --- /dev/null +++ b/src/main/java/com/tikitaka/naechinso/infra/image/AwsS3Service.java @@ -0,0 +1,21 @@ +package com.tikitaka.naechinso.infra.image; + +import org.springframework.web.multipart.MultipartFile; +import java.util.List; + +public interface AwsS3Service { + + /** + * 파일 여러 개를 리스트로 가져와 업로드한 파일명 리스트를 반환합니다 + * @param multipartFiles 멀티 파트 파일 헤더 설정한 업로드 파일 리스트 + * @param dirName 업로드 디렉토릴 경로 + * @return fileNameList BaseURL 을 제외한 파일 경로 리스트 + * */ + List uploadImage(List multipartFiles, String dirName); + + /** + * 지정한 파일 명에 해당하는 파일을 S3 버킷에서 제거합니다 + * @param fileName 디렉토리 경로를 포함한 파일명 + * */ + void deleteImage(String fileName); +} diff --git a/src/main/java/com/tikitaka/naechinso/infra/image/AwsS3ServiceImpl.java b/src/main/java/com/tikitaka/naechinso/infra/image/AwsS3ServiceImpl.java new file mode 100644 index 0000000..a36964b --- /dev/null +++ b/src/main/java/com/tikitaka/naechinso/infra/image/AwsS3ServiceImpl.java @@ -0,0 +1,79 @@ +package com.tikitaka.naechinso.infra.image; + +import com.amazonaws.services.s3.AmazonS3; +import com.amazonaws.services.s3.model.CannedAccessControlList; +import com.amazonaws.services.s3.model.DeleteObjectRequest; +import com.amazonaws.services.s3.model.ObjectMetadata; +import com.amazonaws.services.s3.model.PutObjectRequest; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.http.HttpStatus; +import org.springframework.stereotype.Service; +import org.springframework.web.multipart.MultipartFile; +import org.springframework.web.server.ResponseStatusException; + +import java.io.IOException; +import java.io.InputStream; +import java.util.ArrayList; +import java.util.List; +import java.util.UUID; + +@Slf4j +@Service +@RequiredArgsConstructor +public class AwsS3ServiceImpl implements AwsS3Service { + + @Value("${cloud.aws.s3.bucket}") + private String bucket; + private final AmazonS3 amazonS3; + public List uploadImage(List multipartFiles, String dirName) { + List fileNameList = new ArrayList<>(); + + multipartFiles.forEach(file -> { + String fileName = createFileName(file.getOriginalFilename(), dirName); + ObjectMetadata objectMetadata = new ObjectMetadata(); + objectMetadata.setContentLength(file.getSize()); + objectMetadata.setContentType(file.getContentType()); + + try(InputStream inputStream = file.getInputStream()) { + amazonS3.putObject(new PutObjectRequest(bucket, fileName, inputStream, objectMetadata) + .withCannedAcl(CannedAccessControlList.PublicRead)); + } catch(IOException e) { + throw new ResponseStatusException(HttpStatus.INTERNAL_SERVER_ERROR, "이미지 업로드에 실패했습니다."); + } + + fileNameList.add(fileName); + }); + + return fileNameList; + } + + public void deleteImage(String fileName) { + amazonS3.deleteObject(new DeleteObjectRequest(bucket, fileName)); + } + + + /** + * 파일 명 앞에 Random UUID 를 붙인 파일명을 반환합니다 + * @param fileName 파일 명 + * @param dirName 디렉토리 명 + * @return BaseURL 제외한 디렉토리명 과 UUID 를 합한 최종 파일 경로 + * */ + private String createFileName(String fileName, String dirName) { + return dirName + "/" + UUID.randomUUID() + getFileExtension(fileName); + } + + /** + * 파일 확장자를 가져옵니다 + * @param fileName 파일 명 + * @return 파일 확장자 + * */ + private String getFileExtension(String fileName) { + try { + return fileName.substring(fileName.lastIndexOf(".")); + } catch (StringIndexOutOfBoundsException e) { + throw new ResponseStatusException(HttpStatus.BAD_REQUEST, "잘못된 형식의 파일(" + fileName + ") 입니다."); + } + } +} \ No newline at end of file diff --git a/src/main/java/com/tikitaka/naechinso/infra/image/constant/AwsS3Directory.java b/src/main/java/com/tikitaka/naechinso/infra/image/constant/AwsS3Directory.java new file mode 100644 index 0000000..31e545f --- /dev/null +++ b/src/main/java/com/tikitaka/naechinso/infra/image/constant/AwsS3Directory.java @@ -0,0 +1,24 @@ +package com.tikitaka.naechinso.infra.image.constant; + +import com.fasterxml.jackson.annotation.JsonCreator; + +/** + * S3 내부의 디렉토리 경로를 담당하는 Enum 입니다 + * @author gengminy 221008 + * */ +public enum AwsS3Directory { + member, + job, + edu; + + //Enum Validation 을 위한 코드, enum 에 속하지 않으면 null 리턴 + @JsonCreator + public static AwsS3Directory fromS3Directory(String val){ + for(AwsS3Directory awsS3Directory : AwsS3Directory.values()){ + if(awsS3Directory.name().equals(val)){ + return awsS3Directory; + } + } + return null; + } +} diff --git a/src/main/java/com/tikitaka/naechinso/infra/sms/SmsService.java b/src/main/java/com/tikitaka/naechinso/infra/sms/NaverSmsService.java similarity index 73% rename from src/main/java/com/tikitaka/naechinso/infra/sms/SmsService.java rename to src/main/java/com/tikitaka/naechinso/infra/sms/NaverSmsService.java index 24ff8a8..c3602f9 100644 --- a/src/main/java/com/tikitaka/naechinso/infra/sms/SmsService.java +++ b/src/main/java/com/tikitaka/naechinso/infra/sms/NaverSmsService.java @@ -1,5 +1,5 @@ package com.tikitaka.naechinso.infra.sms; -public interface SmsService { +public interface NaverSmsService { boolean sendMessage(String to, String message); } diff --git a/src/main/java/com/tikitaka/naechinso/infra/sms/SmsServiceImpl.java b/src/main/java/com/tikitaka/naechinso/infra/sms/NaverSmsServiceImpl.java similarity index 98% rename from src/main/java/com/tikitaka/naechinso/infra/sms/SmsServiceImpl.java rename to src/main/java/com/tikitaka/naechinso/infra/sms/NaverSmsServiceImpl.java index e3be5ed..0ccf4c8 100644 --- a/src/main/java/com/tikitaka/naechinso/infra/sms/SmsServiceImpl.java +++ b/src/main/java/com/tikitaka/naechinso/infra/sms/NaverSmsServiceImpl.java @@ -23,7 +23,7 @@ @Slf4j @Service @RequiredArgsConstructor -public class SmsServiceImpl implements SmsService { +public class NaverSmsServiceImpl implements NaverSmsService { private final WebClient webClient; @Value("${naver.sms.access-key}") private String accessKey; diff --git a/src/main/resources/application.yml b/src/main/resources/application.yml index 32b0692..16b3960 100644 --- a/src/main/resources/application.yml +++ b/src/main/resources/application.yml @@ -31,3 +31,4 @@ spring: logging.level: org.hibernate.SQL: debug org.hibernate.type: trace + com.amazonaws.util.EC2MetadataUtils: error diff --git a/src/test/java/com/tikitaka/naechinso/unit/service/SmsCertificationServiceTest.java b/src/test/java/com/tikitaka/naechinso/unit/service/SmsCertificationServiceTest.java index c328a43..8d98d8c 100644 --- a/src/test/java/com/tikitaka/naechinso/unit/service/SmsCertificationServiceTest.java +++ b/src/test/java/com/tikitaka/naechinso/unit/service/SmsCertificationServiceTest.java @@ -3,7 +3,6 @@ import com.tikitaka.naechinso.domain.member.MemberRepository; import com.tikitaka.naechinso.domain.member.entity.Member; import com.tikitaka.naechinso.domain.recommend.RecommendService; -import com.tikitaka.naechinso.domain.sms.SmsCertificationService; import com.tikitaka.naechinso.domain.sms.SmsCertificationServiceImpl; import com.tikitaka.naechinso.domain.sms.dto.SmsCertificationRequestDTO; import com.tikitaka.naechinso.domain.sms.dto.SmsCertificationSuccessResponseDTO; @@ -11,18 +10,12 @@ import com.tikitaka.naechinso.global.config.redis.RedisService; import com.tikitaka.naechinso.global.config.security.dto.JwtDTO; import com.tikitaka.naechinso.global.config.security.jwt.JwtTokenProvider; -import com.tikitaka.naechinso.infra.sms.SmsService; -import org.junit.Before; -import org.junit.Rule; import org.junit.jupiter.api.DisplayName; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.extension.ExtendWith; import org.mockito.InjectMocks; import org.mockito.Mock; -import org.mockito.Mockito; -import org.mockito.Spy; import org.mockito.junit.jupiter.MockitoExtension; -import org.springframework.test.util.ReflectionTestUtils; import java.time.Duration; import java.util.ArrayList; From 44b8ac15a1a668948924ae69695749d7b4931d65 Mon Sep 17 00:00:00 2001 From: gengminy Date: Sat, 8 Oct 2022 18:28:21 +0900 Subject: [PATCH 21/72] =?UTF-8?q?:hammer:=20fix(s3):=20=EC=9D=B4=EB=AF=B8?= =?UTF-8?q?=EC=A7=80=20=EC=BB=A8=ED=8A=B8=EB=A1=A4=EB=9F=AC=20URL=20?= =?UTF-8?q?=EC=88=98=EC=A0=95=20#35?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../global/config/security/SecurityConfig.java | 2 +- .../tikitaka/naechinso/global/error/ErrorCode.java | 4 ++++ .../naechinso/infra/image/AwsS3Controller.java | 13 +++++++------ .../naechinso/infra/image/AwsS3Service.java | 1 + .../naechinso/infra/image/AwsS3ServiceImpl.java | 7 +++++-- 5 files changed, 18 insertions(+), 9 deletions(-) diff --git a/src/main/java/com/tikitaka/naechinso/global/config/security/SecurityConfig.java b/src/main/java/com/tikitaka/naechinso/global/config/security/SecurityConfig.java index 8bff31a..1aff70a 100644 --- a/src/main/java/com/tikitaka/naechinso/global/config/security/SecurityConfig.java +++ b/src/main/java/com/tikitaka/naechinso/global/config/security/SecurityConfig.java @@ -57,7 +57,7 @@ public SecurityFilterChain filterChain(HttpSecurity http) throws Exception { .authorizeRequests() .requestMatchers(CorsUtils::isPreFlightRequest).permitAll() .antMatchers(SwaggerPatterns).permitAll() - .antMatchers(HttpMethod.DELETE,"/s3/image").hasAuthority("ROLE_ADMIN") + .antMatchers(HttpMethod.DELETE,"/s3/image/**").hasAuthority("ROLE_ADMIN") .antMatchers("/admin/**").hasAuthority("ROLE_ADMIN") .antMatchers("/member/join").permitAll() .antMatchers("/").permitAll() //health check diff --git a/src/main/java/com/tikitaka/naechinso/global/error/ErrorCode.java b/src/main/java/com/tikitaka/naechinso/global/error/ErrorCode.java index f063d73..3c8f497 100644 --- a/src/main/java/com/tikitaka/naechinso/global/error/ErrorCode.java +++ b/src/main/java/com/tikitaka/naechinso/global/error/ErrorCode.java @@ -64,6 +64,10 @@ public enum ErrorCode { /* Database 관련 오류 */ DUPLICATE_RESOURCE(CONFLICT, "D001", "데이터가 이미 존재합니다"), + /* 이미지 관련 오류 */ + INVALID_FILE_EXTENSION(BAD_REQUEST, "FILE000", "잘못된 파일 확장자명입니다"), + FILE_UPLOAD_FAILED(INTERNAL_SERVER_ERROR, "FILE001", "파일 업로드에 실패했습니다"), + ; diff --git a/src/main/java/com/tikitaka/naechinso/infra/image/AwsS3Controller.java b/src/main/java/com/tikitaka/naechinso/infra/image/AwsS3Controller.java index dfba389..5ea6918 100644 --- a/src/main/java/com/tikitaka/naechinso/infra/image/AwsS3Controller.java +++ b/src/main/java/com/tikitaka/naechinso/infra/image/AwsS3Controller.java @@ -33,14 +33,15 @@ public class AwsS3Controller { * @return 성공 시 200 / 함께 업로드 된 파일의 파일명 리스트 반영 */ @ApiOperation(value = "Amazon S3에 이미지를 업로드한다", notes = "Amazon S3에 이미지 업로드 ") - @PostMapping(value = "/image", consumes = {MediaType.MULTIPART_FORM_DATA_VALUE}) + @PostMapping(value = "/image/{dir}", consumes = {MediaType.MULTIPART_FORM_DATA_VALUE}) public CommonApiResponse> uploadImage( + @PathVariable("dir") AwsS3Directory dirName, @Parameter( description = "업로드 할 파일 리스트", - content = @Content(mediaType = MediaType.APPLICATION_OCTET_STREAM_VALUE) // Won't work without OCTET_STREAM as the mediaType. + // Won't work without OCTET_STREAM as the mediaType. + content = @Content(mediaType = MediaType.APPLICATION_OCTET_STREAM_VALUE) ) @RequestPart List multipartFiles, - @RequestParam AwsS3Directory dirName, @ApiIgnore @AuthMember Member member ) { return CommonApiResponse.of(awsS3ServiceImpl.uploadImage(multipartFiles, dirName.name())); @@ -51,10 +52,10 @@ public CommonApiResponse> uploadImage( * @return 성공 시 200 Success */ @ApiOperation(value = "[Admin] Amazon S3에 업로드 된 파일을 삭제한다", notes = "Amazon S3에 업로드된 이미지 삭제") - @DeleteMapping("/image") + @DeleteMapping("/image/{file}") public CommonApiResponse deleteImage( - @ApiParam(value="img 파일 하나 삭제", required = true) - @RequestParam String fileName + @ApiParam(value="삭제할 서버 내 파일 명", required = true) + @PathVariable("file") String fileName ) { awsS3ServiceImpl.deleteImage(fileName); return CommonApiResponse.of(null); diff --git a/src/main/java/com/tikitaka/naechinso/infra/image/AwsS3Service.java b/src/main/java/com/tikitaka/naechinso/infra/image/AwsS3Service.java index d4915f0..2deb289 100644 --- a/src/main/java/com/tikitaka/naechinso/infra/image/AwsS3Service.java +++ b/src/main/java/com/tikitaka/naechinso/infra/image/AwsS3Service.java @@ -15,6 +15,7 @@ public interface AwsS3Service { /** * 지정한 파일 명에 해당하는 파일을 S3 버킷에서 제거합니다 + * 서버에 존재하지 않는 파일을 삭제 시도하더라도 예외를 내보내지 않습니다 * @param fileName 디렉토리 경로를 포함한 파일명 * */ void deleteImage(String fileName); diff --git a/src/main/java/com/tikitaka/naechinso/infra/image/AwsS3ServiceImpl.java b/src/main/java/com/tikitaka/naechinso/infra/image/AwsS3ServiceImpl.java index a36964b..68c526f 100644 --- a/src/main/java/com/tikitaka/naechinso/infra/image/AwsS3ServiceImpl.java +++ b/src/main/java/com/tikitaka/naechinso/infra/image/AwsS3ServiceImpl.java @@ -5,6 +5,9 @@ import com.amazonaws.services.s3.model.DeleteObjectRequest; import com.amazonaws.services.s3.model.ObjectMetadata; import com.amazonaws.services.s3.model.PutObjectRequest; +import com.tikitaka.naechinso.global.error.ErrorCode; +import com.tikitaka.naechinso.global.error.exception.BadRequestException; +import com.tikitaka.naechinso.global.error.exception.InternalServerException; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; import org.springframework.beans.factory.annotation.Value; @@ -40,7 +43,7 @@ public List uploadImage(List multipartFiles, String dirNa amazonS3.putObject(new PutObjectRequest(bucket, fileName, inputStream, objectMetadata) .withCannedAcl(CannedAccessControlList.PublicRead)); } catch(IOException e) { - throw new ResponseStatusException(HttpStatus.INTERNAL_SERVER_ERROR, "이미지 업로드에 실패했습니다."); + throw new InternalServerException(ErrorCode.FILE_UPLOAD_FAILED); } fileNameList.add(fileName); @@ -73,7 +76,7 @@ private String getFileExtension(String fileName) { try { return fileName.substring(fileName.lastIndexOf(".")); } catch (StringIndexOutOfBoundsException e) { - throw new ResponseStatusException(HttpStatus.BAD_REQUEST, "잘못된 형식의 파일(" + fileName + ") 입니다."); + throw new BadRequestException(ErrorCode.INVALID_FILE_EXTENSION); } } } \ No newline at end of file From 62cf104bb23d07684219e482603509e8d577d8a1 Mon Sep 17 00:00:00 2001 From: gengminy Date: Sun, 9 Oct 2022 13:13:02 +0900 Subject: [PATCH 22/72] =?UTF-8?q?:rocket:=20feat(pend):=20=EC=82=AC?= =?UTF-8?q?=EC=A7=84=20=EC=9D=B8=EC=A6=9D=20=EC=97=94=ED=8B=B0=ED=8B=B0=20?= =?UTF-8?q?=EA=B8=B0=EC=B4=88=20=EA=B5=AC=ED=98=84=20#37?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../domain/member/MemberController.java | 40 +++----- .../domain/member/MemberRepository.java | 1 + .../domain/member/MemberService.java | 89 +++++++++-------- .../member/dto/MemberCommonResponseDTO.java | 6 ++ .../dto/MemberDetailJoinRequestDTO.java | 15 ++- .../member/dto/MemberDetailResponseDTO.java | 27 +++-- .../member/dto/MemberFindResponseDTO.java | 73 ++++++++++++++ ...TO.java => MemberUpdateEduRequestDTO.java} | 2 +- .../dto/MemberUpdateImageRequestDTO.java | 25 +++++ ...TO.java => MemberUpdateJobRequestDTO.java} | 2 +- .../domain/member/entity/Member.java | 49 ++++++--- .../domain/member/entity/MemberDetail.java | 17 +++- .../domain/pending/PendingController.java | 51 ++++++++++ .../domain/pending/PendingRepository.java | 14 +++ .../domain/pending/PendingService.java | 99 +++++++++++++++++++ .../domain/pending/constant/PendingType.java | 21 ++++ .../pending/dto/PendingFindResponseDTO.java | 54 ++++++++++ .../pending/dto/PendingRejectRequestDTO.java | 26 +++++ .../pending/dto/PendingResponseDTO.java | 40 ++++++++ .../PendingUpdateCreditImageRequestDTO.java | 33 +++++++ .../PendingUpdateMemberImageRequestDTO.java | 36 +++++++ .../domain/pending/entity/Pending.java | 71 +++++++++++++ .../domain/recommend/RecommendService.java | 3 - .../dto/RecommendListResponseDTO.java | 4 +- ...ommendMemberAcceptAndUpdateRequestDTO.java | 8 +- .../recommend/dto/RecommendReceiverDTO.java | 2 +- .../domain/recommend/entity/Recommend.java | 19 ---- .../sms/SmsCertificationServiceImpl.java | 2 +- .../SmsCertificationSuccessResponseDTO.java | 3 +- .../config/security/SecurityConfig.java | 1 + .../naechinso/global/error/ErrorCode.java | 7 +- .../naechinso/global/error/ErrorResponse.java | 2 +- .../global/error/GlobalExceptionHandler.java | 2 +- .../unit/service/MemberServiceTest.java | 36 +++++++ 34 files changed, 740 insertions(+), 140 deletions(-) create mode 100644 src/main/java/com/tikitaka/naechinso/domain/member/dto/MemberFindResponseDTO.java rename src/main/java/com/tikitaka/naechinso/domain/member/dto/{MemberEduUpdateRequestDTO.java => MemberUpdateEduRequestDTO.java} (95%) create mode 100644 src/main/java/com/tikitaka/naechinso/domain/member/dto/MemberUpdateImageRequestDTO.java rename src/main/java/com/tikitaka/naechinso/domain/member/dto/{MemberJobUpdateRequestDTO.java => MemberUpdateJobRequestDTO.java} (95%) create mode 100644 src/main/java/com/tikitaka/naechinso/domain/pending/PendingController.java create mode 100644 src/main/java/com/tikitaka/naechinso/domain/pending/PendingRepository.java create mode 100644 src/main/java/com/tikitaka/naechinso/domain/pending/PendingService.java create mode 100644 src/main/java/com/tikitaka/naechinso/domain/pending/constant/PendingType.java create mode 100644 src/main/java/com/tikitaka/naechinso/domain/pending/dto/PendingFindResponseDTO.java create mode 100644 src/main/java/com/tikitaka/naechinso/domain/pending/dto/PendingRejectRequestDTO.java create mode 100644 src/main/java/com/tikitaka/naechinso/domain/pending/dto/PendingResponseDTO.java create mode 100644 src/main/java/com/tikitaka/naechinso/domain/pending/dto/PendingUpdateCreditImageRequestDTO.java create mode 100644 src/main/java/com/tikitaka/naechinso/domain/pending/dto/PendingUpdateMemberImageRequestDTO.java create mode 100644 src/main/java/com/tikitaka/naechinso/domain/pending/entity/Pending.java create mode 100644 src/test/java/com/tikitaka/naechinso/unit/service/MemberServiceTest.java diff --git a/src/main/java/com/tikitaka/naechinso/domain/member/MemberController.java b/src/main/java/com/tikitaka/naechinso/domain/member/MemberController.java index 39a1f47..8328903 100644 --- a/src/main/java/com/tikitaka/naechinso/domain/member/MemberController.java +++ b/src/main/java/com/tikitaka/naechinso/domain/member/MemberController.java @@ -23,7 +23,6 @@ public class MemberController { private final MemberService memberService; - private final RecommendService recommendService; private final JwtTokenProvider jwtTokenService; @@ -37,7 +36,7 @@ public CommonApiResponse getMyInformation( } @GetMapping("/detail") - @ApiOperation(value = "회원가입 세부 정보를 가져온다 (AccessToken 필요)") + @ApiOperation(value = "회원가입 세부 정보를 가져온다 (AccessToken)") public CommonApiResponse getMemberDetail( @ApiIgnore @AuthMember Member member ) { @@ -47,7 +46,7 @@ public CommonApiResponse getMemberDetail( @PostMapping("/join") @ApiOperation(value = "유저를 공통 정보로 가입시킨다 (RegisterToken)") - public CommonApiResponse joinCommonMember( + public CommonApiResponse createCommonMember( HttpServletRequest request, @Valid @RequestBody MemberCommonJoinRequestDTO dto ) { @@ -57,7 +56,7 @@ public CommonApiResponse joinCommonMember( @PostMapping("/join/detail") @ApiOperation(value = "회원가입 세부 정보를 입력하여 최종 가입시킨다 (AccessToken)") - public CommonApiResponse setMemberDetail( + public CommonApiResponse createMemberDetail( @Valid @RequestBody MemberDetailJoinRequestDTO dto, @ApiIgnore @AuthMember Member member ) { @@ -76,8 +75,8 @@ public CommonApiResponse updateCommonMember( @PatchMapping("/job") @ApiOperation(value = "직업 정보를 업데이트 한다 (AccessToken)") - public CommonApiResponse setMemberJob( - @RequestBody MemberJobUpdateRequestDTO dto, + public CommonApiResponse updateJob( + @Valid @RequestBody MemberUpdateJobRequestDTO dto, @ApiIgnore @AuthMember Member member ) { return CommonApiResponse.of(memberService.updateJob(member, dto)); @@ -85,34 +84,27 @@ public CommonApiResponse setMemberJob( @PatchMapping("/edu") @ApiOperation(value = "학력 정보를 업데이트 한다 (AccessToken)") - public CommonApiResponse setMemberJob( - @RequestBody MemberEduUpdateRequestDTO dto, + public CommonApiResponse updateEdu( + @Valid @RequestBody MemberUpdateEduRequestDTO dto, @ApiIgnore @AuthMember Member member ) { return CommonApiResponse.of(memberService.updateEdu(member, dto)); } -// @PostMapping(value = "/image", consumes = {MediaType.MULTIPART_FORM_DATA_VALUE}) -// @ApiOperation(value = "프로필 이미지를 업로드하고 이미지 URL 을 가져온다 (AccessToken)") -// public CommonApiResponse> updateProfileImage( -// @Parameter( -// description = "업로드 파일 리스트", -// content = @Content(mediaType = MediaType.APPLICATION_OCTET_STREAM_VALUE), -// required = true -// ) -// @RequestPart List multipartFile, -// @ApiIgnore @AuthMember Member member -// ) { -//// awsS3Service.uploadImage(multipartFile, dirName); -// return CommonApiResponse.of(null); -// } - + @PatchMapping("/image") + @ApiOperation(value = "프로필 이미지를 업데이트 한다 (AccessToken)") + public CommonApiResponse updateImage( + @Valid @RequestBody MemberUpdateImageRequestDTO dto, + @ApiIgnore @AuthMember Member member + ) { + return CommonApiResponse.of(memberService.updateImage(member, dto)); + } //페이징 처리 추가할 예정 @GetMapping("/find") @ApiOperation(value = "[Admin]현재 가입한 모든 유저를 불러온다 (AccessToken)") - public CommonApiResponse> getMyInformation( + public CommonApiResponse> getMyInformation( // @RequestBody RecommendMemberAcceptRequestDTO dto, // @ApiIgnore @AuthMember Member member ) { diff --git a/src/main/java/com/tikitaka/naechinso/domain/member/MemberRepository.java b/src/main/java/com/tikitaka/naechinso/domain/member/MemberRepository.java index 27cbfc2..9246e5f 100644 --- a/src/main/java/com/tikitaka/naechinso/domain/member/MemberRepository.java +++ b/src/main/java/com/tikitaka/naechinso/domain/member/MemberRepository.java @@ -4,6 +4,7 @@ import org.springframework.data.jpa.repository.JpaRepository; import org.springframework.stereotype.Repository; +import javax.swing.text.html.Option; import java.util.Optional; @Repository diff --git a/src/main/java/com/tikitaka/naechinso/domain/member/MemberService.java b/src/main/java/com/tikitaka/naechinso/domain/member/MemberService.java index 6b2ca5c..59d6b84 100644 --- a/src/main/java/com/tikitaka/naechinso/domain/member/MemberService.java +++ b/src/main/java/com/tikitaka/naechinso/domain/member/MemberService.java @@ -3,21 +3,21 @@ import com.tikitaka.naechinso.domain.member.dto.*; import com.tikitaka.naechinso.domain.member.entity.Member; import com.tikitaka.naechinso.domain.member.entity.MemberDetail; +import com.tikitaka.naechinso.domain.pending.PendingService; +import com.tikitaka.naechinso.domain.pending.constant.PendingType; +import com.tikitaka.naechinso.domain.pending.dto.PendingUpdateCreditImageRequestDTO; +import com.tikitaka.naechinso.domain.pending.dto.PendingUpdateMemberImageRequestDTO; import com.tikitaka.naechinso.global.common.response.TokenResponseDTO; -import com.tikitaka.naechinso.global.config.security.MemberAdapter; import com.tikitaka.naechinso.global.config.security.dto.JwtDTO; import com.tikitaka.naechinso.global.config.security.jwt.JwtTokenProvider; import com.tikitaka.naechinso.global.error.ErrorCode; import com.tikitaka.naechinso.global.error.exception.BadRequestException; +import com.tikitaka.naechinso.global.error.exception.ForbiddenException; import com.tikitaka.naechinso.global.error.exception.NotFoundException; import com.tikitaka.naechinso.global.error.exception.UnauthorizedException; import lombok.RequiredArgsConstructor; -import org.springframework.security.authentication.UsernamePasswordAuthenticationToken; -import org.springframework.security.core.authority.SimpleGrantedAuthority; -import org.springframework.security.core.context.SecurityContextHolder; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; -import org.springframework.web.multipart.MultipartFile; import java.util.List; import java.util.Optional; @@ -28,9 +28,10 @@ @Transactional public class MemberService { + private final JwtTokenProvider jwtTokenProvider; + private final PendingService pendingService; private final MemberRepository memberRepository; private final MemberDetailRepository memberDetailRepository; - private final JwtTokenProvider jwtTokenProvider; public Member findByPhone(String phone) { return memberRepository.findByPhone(phone) @@ -41,9 +42,9 @@ public Member findByMember(Member member) { return findByPhone(member.getPhone()); } - public List findAll() { + public List findAll() { return memberRepository.findAll().stream() - .map(MemberCommonResponseDTO::of).collect(Collectors.toList()); + .map(MemberFindResponseDTO::of).collect(Collectors.toList()); } @@ -78,32 +79,8 @@ public MemberCommonJoinResponseDTO updateCommonMember(Member authMember, MemberU return MemberCommonJoinResponseDTO.of(member); } - public TokenResponseDTO login(String phone) { - - Member checkMember = memberRepository.findByPhone(phone) - .orElseThrow(() -> new BadRequestException(ErrorCode.USER_NOT_FOUND)); - - UsernamePasswordAuthenticationToken authenticationToken - = new UsernamePasswordAuthenticationToken(new MemberAdapter(checkMember), "", List.of(new SimpleGrantedAuthority("ROLE_USER"))); - - SecurityContextHolder.getContext().setAuthentication(authenticationToken); - - TokenResponseDTO tokenResponseDTO - = jwtTokenProvider.generateToken(new JwtDTO(phone)); - - //리프레시 토큰 저장 로직 아래에 - return tokenResponseDTO; - } - - public MemberDetailResponseDTO readDetail(Member member) { -// -// Member checkMember = memberRepository.findByPhone(phone) -// .orElseThrow(() -> new BadRequestException(ErrorCode.USER_NOT_FOUND)); - - MemberDetailResponseDTO dto = MemberDetailResponseDTO.of(member); - - return dto; + return MemberDetailResponseDTO.of(member); } public MemberDetailResponseDTO createDetail(Member authMember, MemberDetailJoinRequestDTO dto) { @@ -115,39 +92,58 @@ public MemberDetailResponseDTO createDetail(Member authMember, MemberDetailJoinR throw new BadRequestException(ErrorCode.USER_ALREADY_EXIST); } + //추천 받은 정보가 없는 회원 + if (member.getRecommendReceived().isEmpty()) { + throw new ForbiddenException(ErrorCode.RECOMMEND_NOT_RECEIVED); + } + MemberDetail detail = MemberDetail.of(member, dto); + + memberDetailRepository.save(detail); return MemberDetailResponseDTO.of(detail); } - public MemberCommonResponseDTO updateJob(Member authMember, MemberJobUpdateRequestDTO dto){ + public MemberCommonResponseDTO updateJob(Member authMember, MemberUpdateJobRequestDTO dto){ //영속성 유지를 위한 fetch Member member = findByMember(authMember); member.updateJob(dto); memberRepository.save(member); + + //직업 정보 승인 요청 + pendingService.createPendingByCreditImage(new PendingUpdateCreditImageRequestDTO(member.getId(), PendingType.JOB, dto.getJobImage())); + return MemberCommonResponseDTO.of(member); } - public MemberCommonResponseDTO updateEdu(Member authMember, MemberEduUpdateRequestDTO dto){ + public MemberCommonResponseDTO updateEdu(Member authMember, MemberUpdateEduRequestDTO dto){ //영속성 유지를 위한 fetch Member member = findByMember(authMember); member.updateEdu(dto); memberRepository.save(member); + + //직업 정보 승인 요청 + pendingService.createPendingByCreditImage(new PendingUpdateCreditImageRequestDTO(member.getId(), PendingType.EDU, dto.getEduImage())); + return MemberCommonResponseDTO.of(member); } /** * MemberDetail 의 프로필 이미지를 업로드 한다 * */ -// public List updateProfileImage(Member authMember, List multipartFile){ -// //영속성 유지를 위한 fetch -// Member member = findByMember(authMember); -// -// memberRepository.save(member); -// return MemberCommonResponseDTO.of(member); -// } + public MemberDetailResponseDTO updateImage(Member authMember, MemberUpdateImageRequestDTO dto){ + //영속성 유지를 위한 fetch + Member member = findByMember(authMember); + member.updateImage(dto.getImages()); + + //프로필 사진 정보 승인 요청 + pendingService.createPendingByMemberImage(new PendingUpdateMemberImageRequestDTO(member.getId(), PendingType.EDU, dto.getImages())); + + memberRepository.save(member); + return MemberDetailResponseDTO.of(member); + } public void validateToken(Member authMember) { @@ -163,4 +159,13 @@ public void validateFormalMember(Member authMember) { } } + public Member findById(Long memberId) { + return memberRepository.findById(memberId) + .orElseThrow(() -> new NotFoundException(ErrorCode.USER_NOT_FOUND)); + } + + public boolean existsById(Long memberId) { + return memberRepository.existsById(memberId); + } + } diff --git a/src/main/java/com/tikitaka/naechinso/domain/member/dto/MemberCommonResponseDTO.java b/src/main/java/com/tikitaka/naechinso/domain/member/dto/MemberCommonResponseDTO.java index dfd6a22..e5881cb 100644 --- a/src/main/java/com/tikitaka/naechinso/domain/member/dto/MemberCommonResponseDTO.java +++ b/src/main/java/com/tikitaka/naechinso/domain/member/dto/MemberCommonResponseDTO.java @@ -36,12 +36,16 @@ public class MemberCommonResponseDTO { private String jobLocation; + private String jobImage; + private String eduName; private String eduMajor; private String eduLevel; + private String eduImage; + public static MemberCommonResponseDTO of(Member member) { MemberCommonResponseDTO res = MemberCommonResponseDTO.builder() @@ -53,9 +57,11 @@ public static MemberCommonResponseDTO of(Member member) { .jobName(member.getJobName()) .jobPart(member.getJobPart()) .jobLocation(member.getJobLocation()) + .jobImage(member.getJobImage()) .eduName(member.getEduName()) .eduMajor(member.getEduMajor()) .eduLevel(member.getEduLevel()) + .eduImage(member.getEduImage()) .build(); return res; diff --git a/src/main/java/com/tikitaka/naechinso/domain/member/dto/MemberDetailJoinRequestDTO.java b/src/main/java/com/tikitaka/naechinso/domain/member/dto/MemberDetailJoinRequestDTO.java index e044e94..da52792 100644 --- a/src/main/java/com/tikitaka/naechinso/domain/member/dto/MemberDetailJoinRequestDTO.java +++ b/src/main/java/com/tikitaka/naechinso/domain/member/dto/MemberDetailJoinRequestDTO.java @@ -7,6 +7,7 @@ import org.hibernate.validator.constraints.Length; import javax.validation.constraints.*; +import java.util.List; /** * 추천 받은 사람의 가입을 위한 Dto입니다 @@ -40,12 +41,15 @@ public class MemberDetailJoinRequestDTO { @NotBlank(message = "주소 정보를 입력해야 합니다") private String address; + @ApiModelProperty(example = "무교") @NotBlank(message = "종교 정보를 입력해야 합니다") private String religion; + @ApiModelProperty(example = "1병") @NotBlank(message = "음주 정보를 입력해야 합니다") private String drink; + @ApiModelProperty(example = "비흡연자") @NotBlank(message = "흡연 정보를 입력해야 합니다") private String smoke; @@ -53,19 +57,24 @@ public class MemberDetailJoinRequestDTO { @Length(max = 4, message = "올바른 MBTI 정보를 입력하세요") private String mbti; + @ApiModelProperty(example = "직관적") @NotBlank(message = "성격 정보를 입력해야 합니다") private String personality; + @ApiModelProperty(example = "반갑습니다") @NotBlank(message = "자기 소개를 입력해야 합니다") private String introduce; + @ApiModelProperty(example = "코딩") @NotBlank(message = "취미 정보를 입력해야 합니다") private String hobby; + @ApiModelProperty(example = "헌신적임") @NotBlank(message = "연애 스타일을 입력해야 합니다") private String style; - @NotBlank(message = "사진을 업로드해야 합니다") - private String picture; - + @ApiModelProperty(example = "[\"img1\", \"img2\", \"img3\"]") + @Size(min = 3, max = 3, message = "사진 3장을 업로드해야 합니다") + @NotNull + private List images; } diff --git a/src/main/java/com/tikitaka/naechinso/domain/member/dto/MemberDetailResponseDTO.java b/src/main/java/com/tikitaka/naechinso/domain/member/dto/MemberDetailResponseDTO.java index 8203075..4ce1f78 100644 --- a/src/main/java/com/tikitaka/naechinso/domain/member/dto/MemberDetailResponseDTO.java +++ b/src/main/java/com/tikitaka/naechinso/domain/member/dto/MemberDetailResponseDTO.java @@ -8,6 +8,9 @@ import com.tikitaka.naechinso.global.error.exception.NotFoundException; import lombok.*; +import java.util.Arrays; +import java.util.List; + /** * 추천인 및 추천 받는 사람 공통 가입을 위한 Dto입니다 * @author gengminy 220924 @@ -50,7 +53,7 @@ public class MemberDetailResponseDTO { private String style; - private String picture; + private List images; private Long point; @@ -68,23 +71,19 @@ public static MemberDetailResponseDTO of(MemberDetail memberDetail) { } private static MemberDetailResponseDTO buildDetail(MemberDetail detail) { - MemberDetailResponseDTOBuilder dtoBuilder = MemberDetailResponseDTO.builder(); Member member = detail.getMember(); - //멤버 정보가 연결되어 있으면 가져옴 - if (member != null) { - dtoBuilder.phone(member.getPhone()) - .role(member.getRole()) - .name(member.getName()) - .gender(member.getGender()) - .age(member.getAge()); - - } else { - //없으면 에러 + //멤버 정보가 없으면 에러 + if (member == null) { throw new NotFoundException(ErrorCode.USER_NOT_FOUND); } - return dtoBuilder + return MemberDetailResponseDTO.builder() + .phone(member.getPhone()) + .role(member.getRole()) + .name(member.getName()) + .gender(member.getGender()) + .age(member.getAge()) .height(detail.getHeight()) .address(detail.getAddress()) .religion(detail.getReligion()) @@ -95,7 +94,7 @@ private static MemberDetailResponseDTO buildDetail(MemberDetail detail) { .introduce(detail.getIntroduce()) .hobby(detail.getHobby()) .style(detail.getStyle()) - .picture(detail.getPicture()) + .images(detail.getImages()) .point(detail.getPoint()) .build(); } diff --git a/src/main/java/com/tikitaka/naechinso/domain/member/dto/MemberFindResponseDTO.java b/src/main/java/com/tikitaka/naechinso/domain/member/dto/MemberFindResponseDTO.java new file mode 100644 index 0000000..ee97e13 --- /dev/null +++ b/src/main/java/com/tikitaka/naechinso/domain/member/dto/MemberFindResponseDTO.java @@ -0,0 +1,73 @@ +package com.tikitaka.naechinso.domain.member.dto; + +import com.tikitaka.naechinso.domain.member.constant.Gender; +import com.tikitaka.naechinso.domain.member.constant.Role; +import com.tikitaka.naechinso.domain.member.entity.Member; +import lombok.*; + +import java.time.LocalDateTime; + +/** + * 멤버 전체 검색을 위한 DTO + * @author gengminy 221008 + * */ +@AllArgsConstructor +@NoArgsConstructor +@Getter +@Builder +@ToString +public class MemberFindResponseDTO { + + private Long id; + + private String phone; + + private Role role; + + private String name; + + private Gender gender; + + private int age; + + private String jobName; + + private String jobPart; + + private String jobLocation; + + private String jobImage; + + private String eduName; + + private String eduMajor; + + private String eduLevel; + + private String eduImage; + + private LocalDateTime createdAt; + + + public static MemberFindResponseDTO of(Member member) { + MemberFindResponseDTO res = MemberFindResponseDTO.builder() + .id(member.getId()) + .phone(member.getPhone()) + .role(member.getRole()) + .name(member.getName()) + .gender(member.getGender()) + .age(member.getAge()) + .jobName(member.getJobName()) + .jobPart(member.getJobPart()) + .jobLocation(member.getJobLocation()) + .jobImage(member.getJobImage()) + .eduName(member.getEduName()) + .eduMajor(member.getEduMajor()) + .eduLevel(member.getEduLevel()) + .eduImage(member.getEduImage()) + .createdAt(member.getCreatedAt()) + .build(); + + return res; + } +} diff --git a/src/main/java/com/tikitaka/naechinso/domain/member/dto/MemberEduUpdateRequestDTO.java b/src/main/java/com/tikitaka/naechinso/domain/member/dto/MemberUpdateEduRequestDTO.java similarity index 95% rename from src/main/java/com/tikitaka/naechinso/domain/member/dto/MemberEduUpdateRequestDTO.java rename to src/main/java/com/tikitaka/naechinso/domain/member/dto/MemberUpdateEduRequestDTO.java index 107a32f..8822f0d 100644 --- a/src/main/java/com/tikitaka/naechinso/domain/member/dto/MemberEduUpdateRequestDTO.java +++ b/src/main/java/com/tikitaka/naechinso/domain/member/dto/MemberUpdateEduRequestDTO.java @@ -14,7 +14,7 @@ @Getter @Builder @ToString -public class MemberEduUpdateRequestDTO { +public class MemberUpdateEduRequestDTO { @ApiModelProperty(example = "서울") @NotBlank(message = "학교명을 입력해주세요") private String eduName; diff --git a/src/main/java/com/tikitaka/naechinso/domain/member/dto/MemberUpdateImageRequestDTO.java b/src/main/java/com/tikitaka/naechinso/domain/member/dto/MemberUpdateImageRequestDTO.java new file mode 100644 index 0000000..17d7aae --- /dev/null +++ b/src/main/java/com/tikitaka/naechinso/domain/member/dto/MemberUpdateImageRequestDTO.java @@ -0,0 +1,25 @@ +package com.tikitaka.naechinso.domain.member.dto; + +import io.swagger.annotations.ApiModelProperty; +import lombok.*; + +import javax.validation.constraints.NotBlank; +import javax.validation.constraints.NotNull; +import javax.validation.constraints.Size; +import java.util.List; + +/** + * 직업 정보 업데이트를 위한 DTO + * @author gengminy 221005 + * */ +@AllArgsConstructor +@NoArgsConstructor +@Getter +@Builder +@ToString +public class MemberUpdateImageRequestDTO { + @ApiModelProperty(example = "[\"img1\", \"img2\", \"img3\"]") + @Size(min = 3, max = 3, message = "사진 3장을 업로드해야 합니다") + @NotNull + private List images; +} diff --git a/src/main/java/com/tikitaka/naechinso/domain/member/dto/MemberJobUpdateRequestDTO.java b/src/main/java/com/tikitaka/naechinso/domain/member/dto/MemberUpdateJobRequestDTO.java similarity index 95% rename from src/main/java/com/tikitaka/naechinso/domain/member/dto/MemberJobUpdateRequestDTO.java rename to src/main/java/com/tikitaka/naechinso/domain/member/dto/MemberUpdateJobRequestDTO.java index fabe08e..36444bd 100644 --- a/src/main/java/com/tikitaka/naechinso/domain/member/dto/MemberJobUpdateRequestDTO.java +++ b/src/main/java/com/tikitaka/naechinso/domain/member/dto/MemberUpdateJobRequestDTO.java @@ -14,7 +14,7 @@ @Getter @Builder @ToString -public class MemberJobUpdateRequestDTO { +public class MemberUpdateJobRequestDTO { @ApiModelProperty(example = "카카오") @NotBlank(message = "직장명을 입력해주세요") private String jobName; diff --git a/src/main/java/com/tikitaka/naechinso/domain/member/entity/Member.java b/src/main/java/com/tikitaka/naechinso/domain/member/entity/Member.java index 5b4d851..6c615f8 100644 --- a/src/main/java/com/tikitaka/naechinso/domain/member/entity/Member.java +++ b/src/main/java/com/tikitaka/naechinso/domain/member/entity/Member.java @@ -4,10 +4,13 @@ import com.tikitaka.naechinso.domain.member.constant.Gender; import com.tikitaka.naechinso.domain.member.constant.Role; import com.tikitaka.naechinso.domain.member.dto.MemberUpdateCommonRequestDTO; -import com.tikitaka.naechinso.domain.member.dto.MemberEduUpdateRequestDTO; -import com.tikitaka.naechinso.domain.member.dto.MemberJobUpdateRequestDTO; +import com.tikitaka.naechinso.domain.member.dto.MemberUpdateEduRequestDTO; +import com.tikitaka.naechinso.domain.member.dto.MemberUpdateJobRequestDTO; +import com.tikitaka.naechinso.domain.pending.entity.Pending; import com.tikitaka.naechinso.domain.recommend.entity.Recommend; import com.tikitaka.naechinso.global.config.entity.BaseEntity; +import com.tikitaka.naechinso.global.error.ErrorCode; +import com.tikitaka.naechinso.global.error.exception.UnauthorizedException; import lombok.*; import javax.persistence.*; @@ -84,7 +87,7 @@ public class Member extends BaseEntity { private String jobImage; @Column(name = "mem_job_accepted") - private String jobAccepted; + private Boolean jobAccepted; @Column(name = "mem_edu_school") private String eduName; @@ -99,22 +102,22 @@ public class Member extends BaseEntity { private String eduImage; @Column(name = "mem_edu_accepted") - private String eduAccepted; + private Boolean eduAccepted; @Column(name = "mem_join_accepted") - private String joinAccepted; + private Boolean joinAccepted; - //마지막으로 관리한 어드민 -// @OneToOne(fetch = FetchType.LAZY) -// @JoinColumn(name = "mem_admin_id") -// @JsonIgnore -// private Member adminId; - - //가입했을 경우 정보 디테일 + //멤버 디테일 정보 @OneToOne(mappedBy = "member") @JoinColumn(name = "mem_detail") private MemberDetail detail; + //내 가입 대기 정보 + @OneToMany(mappedBy = "member") + @JsonIgnore + private List pending = new ArrayList<>(); + + //내가 소개해준 사람들 //mapped by 에는 연관관계 엔티티의 필드명을 적어줌 @OneToMany(mappedBy = "sender") @@ -124,21 +127,21 @@ public class Member extends BaseEntity { //나를 소개해준 사람들 @OneToMany(mappedBy = "receiver") @JsonIgnore //순환참조 방지, 엔티티 프로퍼티 가려줌 - private List recommend_received = new ArrayList<>(); + private List recommendReceived = new ArrayList<>(); public void setDetail(MemberDetail memberDetail) { this.detail = memberDetail; } - public void updateJob(MemberJobUpdateRequestDTO requestDTO) { + public void updateJob(MemberUpdateJobRequestDTO requestDTO) { this.jobName = requestDTO.getJobName(); this.jobLocation = requestDTO.getJobLocation(); this.jobPart = requestDTO.getJobPart(); this.jobImage = requestDTO.getJobImage(); } - public void updateEdu(MemberEduUpdateRequestDTO requestDTO) { + public void updateEdu(MemberUpdateEduRequestDTO requestDTO) { this.eduName = requestDTO.getEduName(); this.eduMajor = requestDTO.getEduMajor(); this.eduLevel = requestDTO.getEduLevel(); @@ -151,4 +154,20 @@ public void updateCommon(MemberUpdateCommonRequestDTO dto) { this.age = dto.getAge(); } + public List updateImage(List images) { + if (this.detail == null) { + throw new UnauthorizedException(ErrorCode._UNAUTHORIZED); + } + return this.detail.updateImage(images); + } + + public void acceptJobImage() { + this.jobAccepted = true; + } + + public void acceptEduImage() { + this.eduAccepted = true; + } + + } diff --git a/src/main/java/com/tikitaka/naechinso/domain/member/entity/MemberDetail.java b/src/main/java/com/tikitaka/naechinso/domain/member/entity/MemberDetail.java index 30a22c2..e4c786e 100644 --- a/src/main/java/com/tikitaka/naechinso/domain/member/entity/MemberDetail.java +++ b/src/main/java/com/tikitaka/naechinso/domain/member/entity/MemberDetail.java @@ -5,9 +5,11 @@ import com.tikitaka.naechinso.domain.point.entity.Point; import com.tikitaka.naechinso.global.config.entity.BaseEntity; import lombok.*; +import org.apache.commons.lang3.StringUtils; import javax.persistence.*; import java.util.ArrayList; +import java.util.Arrays; import java.util.List; /** @@ -67,8 +69,8 @@ public class MemberDetail extends BaseEntity { @Builder.Default private String style = ""; - @Column(name = "mem_picture") - private String picture; + @Column(name = "mem_images") + private String images; @Column(name = "mem_point") @Builder.Default @@ -100,7 +102,7 @@ public static MemberDetail of(MemberDetailJoinRequestDTO dto) { .introduce(dto.getIntroduce()) .hobby(dto.getHobby()) .style(dto.getStyle()) - .picture(dto.getPicture()) + .images(StringUtils.join(dto.getImages(), ",")) .build(); } @@ -116,9 +118,16 @@ public static MemberDetail of(Member member, MemberDetailJoinRequestDTO dto) { .introduce(dto.getIntroduce()) .hobby(dto.getHobby()) .style(dto.getStyle()) - .picture(dto.getPicture()) + .images(StringUtils.join(dto.getImages(), ",")) .member(member) .build(); } + public List getImages() { + return List.of(this.images.split(",")); + } + public List updateImage(List images) { + this.images = StringUtils.join(images, ","); + return images; + } } diff --git a/src/main/java/com/tikitaka/naechinso/domain/pending/PendingController.java b/src/main/java/com/tikitaka/naechinso/domain/pending/PendingController.java new file mode 100644 index 0000000..47d75f5 --- /dev/null +++ b/src/main/java/com/tikitaka/naechinso/domain/pending/PendingController.java @@ -0,0 +1,51 @@ +package com.tikitaka.naechinso.domain.pending; + +import com.tikitaka.naechinso.domain.member.entity.Member; +import com.tikitaka.naechinso.domain.pending.dto.PendingRejectRequestDTO; +import com.tikitaka.naechinso.domain.pending.dto.PendingFindResponseDTO; +import com.tikitaka.naechinso.global.config.CommonApiResponse; +import io.swagger.annotations.ApiOperation; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.springframework.web.bind.annotation.*; + +import java.util.List; + +@Slf4j +@RestController +//@RequestMapping("/admin/pending") +@RequestMapping("/pending") +@RequiredArgsConstructor +public class PendingController { + + private final PendingService pendingService; + + @GetMapping + @ApiOperation(value = "[Admin]모든 가입 대기 정보를 가져온다 (AccessToken)") + public CommonApiResponse> getAllPending( +// @ApiIgnore @AuthMember Member member + ) { + return CommonApiResponse.of(pendingService.findAll()); + } + + @PostMapping + @ApiOperation(value = "[테스트]가입 대기 정보 생성 (AccessToken)") + public CommonApiResponse> createPending( + @RequestBody PendingRejectRequestDTO dto +// @ApiIgnore @AuthMember Member member + ) { + + return CommonApiResponse.of(pendingService.findAll()); + } + + @PostMapping("/accept/{id}") + @ApiOperation(value = "[테스트]요청을 승인한다 (AccessToken)") + public CommonApiResponse acceptPending( + @PathVariable("id") Long id +// @ApiIgnore @AuthMember Member member + ) { + Member member = Member.builder().id(10L).build(); ///// + + return CommonApiResponse.of(pendingService.acceptPending(member, id)); + } +} diff --git a/src/main/java/com/tikitaka/naechinso/domain/pending/PendingRepository.java b/src/main/java/com/tikitaka/naechinso/domain/pending/PendingRepository.java new file mode 100644 index 0000000..427380c --- /dev/null +++ b/src/main/java/com/tikitaka/naechinso/domain/pending/PendingRepository.java @@ -0,0 +1,14 @@ +package com.tikitaka.naechinso.domain.pending; + +import com.tikitaka.naechinso.domain.pending.entity.Pending; +import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.stereotype.Repository; + +import java.util.List; + +@Repository +public interface PendingRepository extends JpaRepository { + List findAllByMemberId(Long memberId); + + List findAllByMemberIdAndIsAcceptedIsTrue(Long memberId); +} diff --git a/src/main/java/com/tikitaka/naechinso/domain/pending/PendingService.java b/src/main/java/com/tikitaka/naechinso/domain/pending/PendingService.java new file mode 100644 index 0000000..74ba2e6 --- /dev/null +++ b/src/main/java/com/tikitaka/naechinso/domain/pending/PendingService.java @@ -0,0 +1,99 @@ +package com.tikitaka.naechinso.domain.pending; + +import com.tikitaka.naechinso.domain.member.MemberRepository; +import com.tikitaka.naechinso.domain.member.entity.Member; +import com.tikitaka.naechinso.domain.pending.dto.PendingFindResponseDTO; +import com.tikitaka.naechinso.domain.pending.dto.PendingUpdateCreditImageRequestDTO; +import com.tikitaka.naechinso.domain.pending.dto.PendingUpdateMemberImageRequestDTO; +import com.tikitaka.naechinso.domain.pending.entity.Pending; +import com.tikitaka.naechinso.global.error.ErrorCode; +import com.tikitaka.naechinso.global.error.exception.BadRequestException; +import com.tikitaka.naechinso.global.error.exception.NotFoundException; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +import java.util.List; +import java.util.stream.Collectors; + +@Slf4j +@Service +@RequiredArgsConstructor +@Transactional +public class PendingService { + + private final MemberRepository memberRepository; + private final PendingRepository pendingRepository; + + /** + * 직장이나 학력 인증 정보 승인을 요청한다 + * */ + public PendingFindResponseDTO createPendingByCreditImage(PendingUpdateCreditImageRequestDTO dto) { + //영속성 컨텍스트 가져오기 + Member member = memberRepository.findById(dto.getMemberId()) + .orElseThrow(() -> new NotFoundException(ErrorCode.USER_NOT_FOUND)); + + Pending pending = Pending.builder() + .member(member) + .type(dto.getType()) + .images(dto.getImages()) + .build(); + + pendingRepository.save(pending); + return PendingFindResponseDTO.of(pending); + } + + /** + * 유저의 프로필 사진 승인을 요청한다 + * */ + public PendingFindResponseDTO createPendingByMemberImage(PendingUpdateMemberImageRequestDTO dto) { + //영속성 컨텍스트 가져오기 + Member member = memberRepository.findById(dto.getMemberId()) + .orElseThrow(() -> new NotFoundException(ErrorCode.USER_NOT_FOUND)); + + Pending pending = Pending.builder() + .member(member) + .type(dto.getType()) + .build(); + pending.updateImage(dto.getImages()); + + pendingRepository.save(pending); + return PendingFindResponseDTO.of(pending); + } + + /** + * 유저의 요청을 승인한다 + * */ + public PendingFindResponseDTO acceptPending(Member adminMember, Long pendingId) { + Pending pending = pendingRepository.findById(pendingId) + .orElseThrow(() -> new NotFoundException(ErrorCode._BAD_REQUEST)); + + //유저 정보가 없는 가입 승인 요청 + if (pending.getMember() == null) { + throw new BadRequestException(ErrorCode.USER_NOT_FOUND); + } + + pending.accept(adminMember); + pendingRepository.save(pending); + + return PendingFindResponseDTO.of(pending); + } + + + + //대기 승인 중인 정보를 모두 가져온다 + public List findAllByMemberIdAndIsAcceptedIsTrue(Long memberId) { + return pendingRepository.findAllByMemberIdAndIsAcceptedIsTrue(memberId) + .stream().map(PendingFindResponseDTO::of).collect(Collectors.toList()); + } + + public List findAllByMemberId(Long memberId) { + return pendingRepository.findAllByMemberId(memberId) + .stream().map(PendingFindResponseDTO::of).collect(Collectors.toList()); + } + public List findAll() { + return pendingRepository.findAll() + .stream().map(PendingFindResponseDTO::of).collect(Collectors.toList()); + } +} diff --git a/src/main/java/com/tikitaka/naechinso/domain/pending/constant/PendingType.java b/src/main/java/com/tikitaka/naechinso/domain/pending/constant/PendingType.java new file mode 100644 index 0000000..1c8142c --- /dev/null +++ b/src/main/java/com/tikitaka/naechinso/domain/pending/constant/PendingType.java @@ -0,0 +1,21 @@ +package com.tikitaka.naechinso.domain.pending.constant; + +import com.fasterxml.jackson.annotation.JsonCreator; +import com.tikitaka.naechinso.infra.image.constant.AwsS3Directory; + +public enum PendingType { + MEMBER, + JOB, + EDU; + + //Enum Validation 을 위한 코드, enum 에 속하지 않으면 null 리턴 + @JsonCreator + public static PendingType fromPendingType(String val){ + for(PendingType pendingType : PendingType.values()){ + if(pendingType.name().equals(val)){ + return pendingType; + } + } + return null; + } +} diff --git a/src/main/java/com/tikitaka/naechinso/domain/pending/dto/PendingFindResponseDTO.java b/src/main/java/com/tikitaka/naechinso/domain/pending/dto/PendingFindResponseDTO.java new file mode 100644 index 0000000..a8e586b --- /dev/null +++ b/src/main/java/com/tikitaka/naechinso/domain/pending/dto/PendingFindResponseDTO.java @@ -0,0 +1,54 @@ +package com.tikitaka.naechinso.domain.pending.dto; + +import com.tikitaka.naechinso.domain.pending.constant.PendingType; +import com.tikitaka.naechinso.domain.pending.entity.Pending; +import lombok.*; + +import java.time.LocalDateTime; +import java.util.List; + +@AllArgsConstructor +@NoArgsConstructor +@Getter +@Builder +@ToString +public class PendingFindResponseDTO { + + private Long id; + + private Long memberId; + + private Long adminId; + + private PendingType type; + + private Boolean isAccepted; + + private String reason; + + private List images; + + + private LocalDateTime createdAt; + + + public static PendingFindResponseDTO of(Pending pending) { + Long memberId; + if (pending.getMember() == null) { + memberId = null; + } else { + memberId = pending.getMember().getId(); + } + + return PendingFindResponseDTO.builder() + .id(pending.getId()) + .memberId(memberId) + .type(pending.getType()) + .isAccepted(pending.getIsAccepted()) + .reason(pending.getReason()) + .images(pending.getImages()) + .adminId(pending.getAdminId()) + .createdAt(pending.getCreatedAt()) + .build(); + } +} diff --git a/src/main/java/com/tikitaka/naechinso/domain/pending/dto/PendingRejectRequestDTO.java b/src/main/java/com/tikitaka/naechinso/domain/pending/dto/PendingRejectRequestDTO.java new file mode 100644 index 0000000..36888a2 --- /dev/null +++ b/src/main/java/com/tikitaka/naechinso/domain/pending/dto/PendingRejectRequestDTO.java @@ -0,0 +1,26 @@ +package com.tikitaka.naechinso.domain.pending.dto; + +import com.tikitaka.naechinso.domain.pending.constant.PendingType; +import com.tikitaka.naechinso.domain.pending.entity.Pending; +import lombok.*; + +import java.util.List; + +@AllArgsConstructor +@NoArgsConstructor +@Getter +@Builder +@ToString +public class PendingRejectRequestDTO { + + private PendingType type; + + private Boolean isAccepted; + + private String reason; + + private List images; + + private Long adminId; + +} diff --git a/src/main/java/com/tikitaka/naechinso/domain/pending/dto/PendingResponseDTO.java b/src/main/java/com/tikitaka/naechinso/domain/pending/dto/PendingResponseDTO.java new file mode 100644 index 0000000..b5cdcbd --- /dev/null +++ b/src/main/java/com/tikitaka/naechinso/domain/pending/dto/PendingResponseDTO.java @@ -0,0 +1,40 @@ +package com.tikitaka.naechinso.domain.pending.dto; + +import com.tikitaka.naechinso.domain.pending.constant.PendingType; +import com.tikitaka.naechinso.domain.pending.entity.Pending; +import lombok.*; + +import java.time.LocalDateTime; +import java.util.List; + +@AllArgsConstructor +@NoArgsConstructor +@Getter +@Builder +@ToString +public class PendingResponseDTO { + + private PendingType type; + + private Boolean isAccepted; + + private String reason; + + private List images; + + private Long adminId; + + private LocalDateTime createdAt; + + + public static PendingFindResponseDTO of(Pending pending) { + return PendingFindResponseDTO.builder() + .type(pending.getType()) + .isAccepted(pending.getIsAccepted()) + .reason(pending.getReason()) + .images(pending.getImages()) + .adminId(pending.getAdminId()) + .createdAt(pending.getCreatedAt()) + .build(); + } +} diff --git a/src/main/java/com/tikitaka/naechinso/domain/pending/dto/PendingUpdateCreditImageRequestDTO.java b/src/main/java/com/tikitaka/naechinso/domain/pending/dto/PendingUpdateCreditImageRequestDTO.java new file mode 100644 index 0000000..828adea --- /dev/null +++ b/src/main/java/com/tikitaka/naechinso/domain/pending/dto/PendingUpdateCreditImageRequestDTO.java @@ -0,0 +1,33 @@ +package com.tikitaka.naechinso.domain.pending.dto; + +import com.tikitaka.naechinso.domain.pending.constant.PendingType; +import com.tikitaka.naechinso.global.annotation.Enum; +import io.swagger.annotations.ApiModelProperty; +import lombok.*; + +import javax.validation.constraints.*; +import java.util.List; + +/** + * 유저의 직장 정보나 학교 인증 정보를 업데이트 할 때 + * 어드민의 승인을 받기 위한 Pending 엔티티 생성을 요청하는 DTO + * @author gengminy 221008 + * */ +@AllArgsConstructor +@NoArgsConstructor +@Getter +@Builder +@ToString +public class PendingUpdateCreditImageRequestDTO { + @ApiModelProperty(example = "1") + @Positive(message = "올바르지 않은 id 형식입니다") + private Long memberId; + + @ApiModelProperty(example = "job") + @Enum(enumClass = PendingType.class, message = "승인 요청 타입이 올바르지 않습니다") + private PendingType type; + + @ApiModelProperty(example = "img1") + @NotEmpty + private String images; +} diff --git a/src/main/java/com/tikitaka/naechinso/domain/pending/dto/PendingUpdateMemberImageRequestDTO.java b/src/main/java/com/tikitaka/naechinso/domain/pending/dto/PendingUpdateMemberImageRequestDTO.java new file mode 100644 index 0000000..88c08ad --- /dev/null +++ b/src/main/java/com/tikitaka/naechinso/domain/pending/dto/PendingUpdateMemberImageRequestDTO.java @@ -0,0 +1,36 @@ +package com.tikitaka.naechinso.domain.pending.dto; + +import com.tikitaka.naechinso.domain.pending.constant.PendingType; +import com.tikitaka.naechinso.global.annotation.Enum; +import io.swagger.annotations.ApiModelProperty; +import lombok.*; + +import javax.validation.constraints.NotNull; +import javax.validation.constraints.Positive; +import javax.validation.constraints.Size; +import java.util.List; + +/** + * 유저 프로필 사진을 업로드 할 때 + * 어드민의 승인을 받기 위한 Pending 엔티티 생성을 요청하는 DTO + * @author gengminy 221008 + * */ +@AllArgsConstructor +@NoArgsConstructor +@Getter +@Builder +@ToString +public class PendingUpdateMemberImageRequestDTO { + @ApiModelProperty(example = "1") + @Positive(message = "올바르지 않은 id 형식입니다") + private Long memberId; + + @ApiModelProperty(example = "member") + @Enum(enumClass = PendingType.class, message = "승인 요청 타입이 올바르지 않습니다") + private PendingType type; + + @ApiModelProperty(example = "[\"img1\", \"img2\", \"img3\"]") + @Size(min = 3, max = 3, message = "사진 3장을 업로드해야 합니다") + @NotNull + private List images; +} diff --git a/src/main/java/com/tikitaka/naechinso/domain/pending/entity/Pending.java b/src/main/java/com/tikitaka/naechinso/domain/pending/entity/Pending.java new file mode 100644 index 0000000..0bfed08 --- /dev/null +++ b/src/main/java/com/tikitaka/naechinso/domain/pending/entity/Pending.java @@ -0,0 +1,71 @@ +package com.tikitaka.naechinso.domain.pending.entity; + +import com.fasterxml.jackson.annotation.JsonIgnore; +import com.tikitaka.naechinso.domain.member.entity.Member; +import com.tikitaka.naechinso.domain.pending.constant.PendingType; +import com.tikitaka.naechinso.global.config.entity.BaseEntity; +import com.tikitaka.naechinso.global.error.ErrorCode; +import com.tikitaka.naechinso.global.error.exception.UnauthorizedException; +import lombok.*; +import org.apache.commons.lang3.StringUtils; + +import javax.persistence.*; +import java.util.List; +import java.util.Objects; + +@Entity +@Table(name = "pending") +@Getter +@Builder +@AllArgsConstructor +@NoArgsConstructor +@ToString(exclude = {"member"}) +@EqualsAndHashCode +public class Pending extends BaseEntity { + + @Id + @Column(name = "pen_id") + @GeneratedValue + private Long id; + + //가입 대기 중인 타켓 + @ManyToOne(fetch = FetchType.LAZY) + @JoinColumn(name = "mem_id") + @JsonIgnore + private Member member; + + @Column(name = "pen_type") + private PendingType type; + + @Column(name = "pen_is_accepted") + @Builder.Default + private Boolean isAccepted = false; + + @Column(name = "pen_reason") + private String reason; + + @Column(name = "pen_images") + private String images; + + //마지막으로 관리한 어드민 정보 + @Column(name = "pen_admin_id") + private Long adminId; + + public List getImages() { + return List.of(this.images.split(",")); + } + + public List updateImage(List images) { + this.images = StringUtils.join(images, ","); + return images; + } + + public void accept(Member adminMember) { + //어드민이 아니면 거부 +// if (!Objects.equals(adminMember.getRole().getDetail(), "ROLE_ADMIN")) { +// throw new UnauthorizedException(ErrorCode.UNAUTHORIZED_USER); +// } + this.isAccepted = true; + this.adminId = adminMember.getId(); + } +} diff --git a/src/main/java/com/tikitaka/naechinso/domain/recommend/RecommendService.java b/src/main/java/com/tikitaka/naechinso/domain/recommend/RecommendService.java index 12032fd..a47e430 100644 --- a/src/main/java/com/tikitaka/naechinso/domain/recommend/RecommendService.java +++ b/src/main/java/com/tikitaka/naechinso/domain/recommend/RecommendService.java @@ -2,8 +2,6 @@ import com.tikitaka.naechinso.domain.member.MemberRepository; import com.tikitaka.naechinso.domain.member.MemberService; -import com.tikitaka.naechinso.domain.member.dto.MemberJobUpdateRequestDTO; -import com.tikitaka.naechinso.domain.recommend.dto.RecommendMemberAcceptRequestDTO; import com.tikitaka.naechinso.domain.member.entity.Member; import com.tikitaka.naechinso.domain.recommend.dto.*; import com.tikitaka.naechinso.domain.recommend.entity.Recommend; @@ -18,7 +16,6 @@ import java.util.ArrayList; import java.util.List; -import java.util.Optional; import java.util.stream.Collectors; @Slf4j diff --git a/src/main/java/com/tikitaka/naechinso/domain/recommend/dto/RecommendListResponseDTO.java b/src/main/java/com/tikitaka/naechinso/domain/recommend/dto/RecommendListResponseDTO.java index bbc1a53..73fee52 100644 --- a/src/main/java/com/tikitaka/naechinso/domain/recommend/dto/RecommendListResponseDTO.java +++ b/src/main/java/com/tikitaka/naechinso/domain/recommend/dto/RecommendListResponseDTO.java @@ -20,11 +20,11 @@ public static RecommendListResponseDTO of(Member member) { List recommendList = new ArrayList<>(); List recommendReceivedList = new ArrayList<>(); - member.getRecommends().stream().forEach(recommend -> + member.getRecommends().forEach(recommend -> recommendList.add(RecommendResponseDTO.of(recommend)) ); - member.getRecommend_received().stream().forEach(recommend -> + member.getRecommendReceived().forEach(recommend -> recommendReceivedList.add(RecommendResponseDTO.of(recommend)) ); diff --git a/src/main/java/com/tikitaka/naechinso/domain/recommend/dto/RecommendMemberAcceptAndUpdateRequestDTO.java b/src/main/java/com/tikitaka/naechinso/domain/recommend/dto/RecommendMemberAcceptAndUpdateRequestDTO.java index 7097f9c..75606fc 100644 --- a/src/main/java/com/tikitaka/naechinso/domain/recommend/dto/RecommendMemberAcceptAndUpdateRequestDTO.java +++ b/src/main/java/com/tikitaka/naechinso/domain/recommend/dto/RecommendMemberAcceptAndUpdateRequestDTO.java @@ -1,7 +1,7 @@ package com.tikitaka.naechinso.domain.recommend.dto; -import com.tikitaka.naechinso.domain.member.dto.MemberEduUpdateRequestDTO; -import com.tikitaka.naechinso.domain.member.dto.MemberJobUpdateRequestDTO; +import com.tikitaka.naechinso.domain.member.dto.MemberUpdateEduRequestDTO; +import com.tikitaka.naechinso.domain.member.dto.MemberUpdateJobRequestDTO; import io.swagger.annotations.ApiModelProperty; import lombok.*; @@ -16,10 +16,10 @@ public class RecommendMemberAcceptAndUpdateRequestDTO { @ApiModelProperty - private MemberEduUpdateRequestDTO edu; + private MemberUpdateEduRequestDTO edu; @ApiModelProperty - private MemberJobUpdateRequestDTO job; + private MemberUpdateJobRequestDTO job; // @NotBlank(message = "직장명을 입력해주세요") // private String jobName; diff --git a/src/main/java/com/tikitaka/naechinso/domain/recommend/dto/RecommendReceiverDTO.java b/src/main/java/com/tikitaka/naechinso/domain/recommend/dto/RecommendReceiverDTO.java index b33473a..858aa4c 100644 --- a/src/main/java/com/tikitaka/naechinso/domain/recommend/dto/RecommendReceiverDTO.java +++ b/src/main/java/com/tikitaka/naechinso/domain/recommend/dto/RecommendReceiverDTO.java @@ -23,7 +23,7 @@ public static RecommendReceiverDTO of(Recommend recommend) { return RecommendReceiverDTO.builder() .name(recommend.getReceiverName()) .gender(recommend.getReceiverGender()) - .name(recommend.getReceiverName()) + .age(recommend.getReceiverAge()) .build(); } } diff --git a/src/main/java/com/tikitaka/naechinso/domain/recommend/entity/Recommend.java b/src/main/java/com/tikitaka/naechinso/domain/recommend/entity/Recommend.java index b0eefcf..b679a64 100644 --- a/src/main/java/com/tikitaka/naechinso/domain/recommend/entity/Recommend.java +++ b/src/main/java/com/tikitaka/naechinso/domain/recommend/entity/Recommend.java @@ -99,23 +99,4 @@ public void update(RecommendAcceptRequestDTO requestDTO) { this.receiverPersonality = requestDTO.getPersonality(); this.receiverPeriod = requestDTO.getPeriod(); } - - public void update(Member sender, RecommendMemberAcceptRequestDTO requestDTO) { - updateSender(sender); - this.receiverAppeal = requestDTO.getAppeal(); - this.receiverMeet = requestDTO.getMeet(); - this.receiverPersonality = requestDTO.getPersonality(); - this.receiverPeriod = requestDTO.getPeriod(); - } - - public void updateSender(Member sender) { - this.sender = sender; - this.senderPhone = sender.getPhone(); - this.senderName = sender.getName(); - this.senderAge = sender.getAge(); - this.senderGender = sender.getGender(); - this.senderJobName = sender.getJobName(); - this.senderJobPart = sender.getJobPart(); - this.senderJobLocation = sender.getJobLocation(); - } } diff --git a/src/main/java/com/tikitaka/naechinso/domain/sms/SmsCertificationServiceImpl.java b/src/main/java/com/tikitaka/naechinso/domain/sms/SmsCertificationServiceImpl.java index 323fba3..117d8e7 100644 --- a/src/main/java/com/tikitaka/naechinso/domain/sms/SmsCertificationServiceImpl.java +++ b/src/main/java/com/tikitaka/naechinso/domain/sms/SmsCertificationServiceImpl.java @@ -128,7 +128,7 @@ public SmsCertificationSuccessResponseDTO verifyCode(SmsCertificationRequestDTO //가입 여부 (detail == null) 확인 후 받은 추천서 꺼내옴 final Boolean hasDetail = authMember.getDetail() != null; - //유저 밴 여부 + //유저 밴 여부 가져오기 final Boolean isBanned = false; //액세스 + 리프레시 토큰 반환 diff --git a/src/main/java/com/tikitaka/naechinso/domain/sms/dto/SmsCertificationSuccessResponseDTO.java b/src/main/java/com/tikitaka/naechinso/domain/sms/dto/SmsCertificationSuccessResponseDTO.java index 691cdb6..e201a86 100644 --- a/src/main/java/com/tikitaka/naechinso/domain/sms/dto/SmsCertificationSuccessResponseDTO.java +++ b/src/main/java/com/tikitaka/naechinso/domain/sms/dto/SmsCertificationSuccessResponseDTO.java @@ -19,9 +19,10 @@ public class SmsCertificationSuccessResponseDTO { private String refreshToken; private String registerToken; - //추천 받았는지 여부, true 면 유효한 유저 + //내 번호로 추천받은 정보 리스트 private List recommendReceived = new ArrayList<>(); //가입 완료했는지 여부, detail 정보가 있으면 true private Boolean isActive = false; + //서버로부터 차단 당했는지 여부 private Boolean isBanned = false; } diff --git a/src/main/java/com/tikitaka/naechinso/global/config/security/SecurityConfig.java b/src/main/java/com/tikitaka/naechinso/global/config/security/SecurityConfig.java index 1aff70a..d3897d3 100644 --- a/src/main/java/com/tikitaka/naechinso/global/config/security/SecurityConfig.java +++ b/src/main/java/com/tikitaka/naechinso/global/config/security/SecurityConfig.java @@ -59,6 +59,7 @@ public SecurityFilterChain filterChain(HttpSecurity http) throws Exception { .antMatchers(SwaggerPatterns).permitAll() .antMatchers(HttpMethod.DELETE,"/s3/image/**").hasAuthority("ROLE_ADMIN") .antMatchers("/admin/**").hasAuthority("ROLE_ADMIN") + .antMatchers("/pending/**").permitAll() ///////////////////////////////////////가입승인대기 .antMatchers("/member/join").permitAll() .antMatchers("/").permitAll() //health check .antMatchers("/sms/**").permitAll() diff --git a/src/main/java/com/tikitaka/naechinso/global/error/ErrorCode.java b/src/main/java/com/tikitaka/naechinso/global/error/ErrorCode.java index 3c8f497..9d68814 100644 --- a/src/main/java/com/tikitaka/naechinso/global/error/ErrorCode.java +++ b/src/main/java/com/tikitaka/naechinso/global/error/ErrorCode.java @@ -17,7 +17,7 @@ public enum ErrorCode { _UNAUTHORIZED(UNAUTHORIZED, "C002", "권한이 없습니다"), _METHOD_NOT_ALLOWED(METHOD_NOT_ALLOWED, "C003", "지원하지 않는 Http Method 입니다"), - _UNSUPPORTED_MEDIA_TYPE(UNSUPPORTED_MEDIA_TYPE, "C004", "지원하지 않는 Http Media Type 입니다"), + _UNSUPPORTED_MEDIA_TYPE(UNSUPPORTED_MEDIA_TYPE, "C004", "지원하지 않는 Http Media PendingType 입니다"), _INVALID_REQUEST_PARAMETER(BAD_REQUEST, "C005", "유효하지 않은 Request Parameter 입니다"), CANNOT_CREATE_RECOMMEND(INTERNAL_SERVER_ERROR, "C006", "추천사 작성에 실패했습니다"), CANNOT_CREATE_RECOMMEND_REQUEST(INTERNAL_SERVER_ERROR, "C007", "추천사 요청에 실패했습니다"), @@ -40,7 +40,7 @@ public enum ErrorCode { EXPIRED_VERIFICATION_CODE(UNAUTHORIZED, "AUTH011", "인증번호가 만료되었습니다"), INVALID_USER_TOKEN(UNAUTHORIZED, "AUTH012", "서버에 토큰과 일치하는 정보가 없습니다"), - LOGIN_FAILED(UNAUTHORIZED, "AUTH012", "로그인에 실패했습니다"), + LOGIN_FAILED(UNAUTHORIZED, "AUTH013", "로그인에 실패했습니다"), /* User 관련 오류 */ @@ -51,12 +51,13 @@ public enum ErrorCode { /* Recommend 관련 오류 */ - RECOMMEND_NOT_FOUND(NOT_FOUND, "R000","해당 추천사 정보를 찾을 수 없습니다"), + RECOMMEND_NOT_FOUND(NOT_FOUND, "R000","추천사 정보를 찾을 수 없습니다"), RECOMMEND_ALREADY_EXIST(BAD_REQUEST, "R001","추천사를 같은 사람에게 중복으로 보낼 수 없습니다"), CANNOT_RECOMMEND_MYSELF(BAD_REQUEST, "R002","자기 자신은 추천할 수 없습니다"), RECOMMEND_SENDER_ALREADY_EXIST(BAD_REQUEST, "R003","유저 추천사는 한 번만 작성할 수 있습니다"), RECOMMEND_RECEIVER_NOT_EXIST(BAD_REQUEST, "R004","추천 받을 사람이 존재하지 않습니다"), RECOMMEND_REQUEST_ALREADY_EXIST(BAD_REQUEST, "R005","추천사 요청은 한 번만 보낼 수 있습니다"), + RECOMMEND_NOT_RECEIVED(FORBIDDEN, "R006","가입하기 위해서는 먼저 추천사를 받아야 합니다"), /* Validation 오류 */ PARAMETER_NOT_VALID(BAD_REQUEST, "P000", "인자가 유효하지 않습니다"), diff --git a/src/main/java/com/tikitaka/naechinso/global/error/ErrorResponse.java b/src/main/java/com/tikitaka/naechinso/global/error/ErrorResponse.java index 45875ea..bae4e5b 100644 --- a/src/main/java/com/tikitaka/naechinso/global/error/ErrorResponse.java +++ b/src/main/java/com/tikitaka/naechinso/global/error/ErrorResponse.java @@ -32,7 +32,7 @@ public static ErrorResponse of(ErrorCode errorCode) { .message(errorCode.getDetail()) .status(errorCode.getHttpStatus().value()) .code(errorCode.getCode()) - .errors(Arrays.asList()) + .errors(List.of()) .build(); } diff --git a/src/main/java/com/tikitaka/naechinso/global/error/GlobalExceptionHandler.java b/src/main/java/com/tikitaka/naechinso/global/error/GlobalExceptionHandler.java index dc27c7f..96802cf 100644 --- a/src/main/java/com/tikitaka/naechinso/global/error/GlobalExceptionHandler.java +++ b/src/main/java/com/tikitaka/naechinso/global/error/GlobalExceptionHandler.java @@ -79,7 +79,7 @@ protected ResponseEntity handleHttpRequestMethodNotSupportedExcep } /** - * 지원하지 않은 HTTP Media Type 호출 할 경우 발생 + * 지원하지 않은 HTTP Media PendingType 호출 할 경우 발생 */ @ExceptionHandler(HttpMediaTypeNotSupportedException.class) protected ResponseEntity handleHttpMediaTypeNotSupportedException(HttpMediaTypeNotSupportedException e) { diff --git a/src/test/java/com/tikitaka/naechinso/unit/service/MemberServiceTest.java b/src/test/java/com/tikitaka/naechinso/unit/service/MemberServiceTest.java new file mode 100644 index 0000000..0612d95 --- /dev/null +++ b/src/test/java/com/tikitaka/naechinso/unit/service/MemberServiceTest.java @@ -0,0 +1,36 @@ +package com.tikitaka.naechinso.unit.service; + +import com.tikitaka.naechinso.domain.member.entity.Member; +import com.tikitaka.naechinso.domain.member.entity.MemberDetail; +import com.tikitaka.naechinso.domain.sms.dto.SmsCertificationRequestDTO; +import com.tikitaka.naechinso.domain.sms.dto.SmsCertificationSuccessResponseDTO; +import com.tikitaka.naechinso.global.common.response.TokenResponseDTO; +import com.tikitaka.naechinso.global.config.security.dto.JwtDTO; +import org.apache.commons.lang3.StringUtils; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; +import org.mockito.junit.jupiter.MockitoExtension; + +import java.util.Arrays; +import java.util.List; + +@ExtendWith(MockitoExtension.class) +public class MemberServiceTest { + + @DisplayName("멤버 디테일 문자열 변환 테스트") + @Test + void testVerifyCodeBySignedUpMember() { + String[] str = {"123", "456", "789"}; + MemberDetail memberDetail = MemberDetail.builder() + .images(Arrays.toString(str)) + .build(); + + System.out.println("str = " + Arrays.toString(str)); + + System.out.println(List.of(Arrays.toString(str).split(", "))); + + System.out.println("StringUtils.join(str, \",\") = " + StringUtils.join(str, ",")); + System.out.println("StringUtils.join(str, \",\").split(\",\") = " + Arrays.toString(StringUtils.join(str, ",").split(","))); + } +} From 9d51f617ae6fdd6988751cca59b16f3bde741ccb Mon Sep 17 00:00:00 2001 From: gengminy Date: Mon, 10 Oct 2022 18:26:16 +0900 Subject: [PATCH 23/72] =?UTF-8?q?:rocket:=20feat(pend):=20=EC=82=AC?= =?UTF-8?q?=EC=A7=84=20=EC=9D=B8=EC=A6=9D=20=EC=84=9C=EB=B9=84=EC=8A=A4=20?= =?UTF-8?q?=EA=B5=AC=ED=98=84=20=EB=B0=8F=20=EC=97=B0=EA=B2=B0=20#37?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../naechinso/domain/TestController.java | 219 ++++++++++++++++++ .../domain/member/MemberController.java | 18 +- .../domain/member/MemberService.java | 77 +++--- .../member/dto/MemberCommonResponseDTO.java | 13 +- .../member/dto/MemberUpdateEduRequestDTO.java | 23 ++ .../dto/MemberUpdateImageRequestDTO.java | 4 + .../member/dto/MemberUpdateJobRequestDTO.java | 22 ++ .../domain/member/entity/Member.java | 13 +- .../domain/member/entity/MemberDetail.java | 11 +- .../domain/pending/PendingController.java | 19 +- .../domain/pending/PendingRepository.java | 1 + .../domain/pending/PendingService.java | 116 ++++++++-- .../pending/dto/PendingFindResponseDTO.java | 20 +- .../pending/dto/PendingResponseDTO.java | 8 +- .../dto/PendingUpdateEduRequestDTO.java | 39 ++++ ...O.java => PendingUpdateJobRequestDTO.java} | 10 +- .../domain/pending/entity/Pending.java | 21 +- .../recommend/dto/RecommendReceiverDTO.java | 15 +- .../config/security/SecurityConfig.java | 3 +- .../config/security/jwt/JwtTokenProvider.java | 2 - .../naechinso/global/error/ErrorCode.java | 3 + 21 files changed, 561 insertions(+), 96 deletions(-) create mode 100644 src/main/java/com/tikitaka/naechinso/domain/TestController.java create mode 100644 src/main/java/com/tikitaka/naechinso/domain/pending/dto/PendingUpdateEduRequestDTO.java rename src/main/java/com/tikitaka/naechinso/domain/pending/dto/{PendingUpdateCreditImageRequestDTO.java => PendingUpdateJobRequestDTO.java} (79%) diff --git a/src/main/java/com/tikitaka/naechinso/domain/TestController.java b/src/main/java/com/tikitaka/naechinso/domain/TestController.java new file mode 100644 index 0000000..14fe499 --- /dev/null +++ b/src/main/java/com/tikitaka/naechinso/domain/TestController.java @@ -0,0 +1,219 @@ +package com.tikitaka.naechinso.domain; + +import com.tikitaka.naechinso.domain.member.MemberService; +import com.tikitaka.naechinso.domain.member.constant.Gender; +import com.tikitaka.naechinso.domain.member.dto.MemberCommonJoinRequestDTO; +import com.tikitaka.naechinso.domain.member.dto.MemberCommonJoinResponseDTO; +import com.tikitaka.naechinso.domain.member.dto.MemberUpdateJobRequestDTO; +import com.tikitaka.naechinso.domain.member.entity.Member; +import com.tikitaka.naechinso.domain.pending.PendingService; +import com.tikitaka.naechinso.domain.recommend.RecommendService; +import com.tikitaka.naechinso.domain.recommend.dto.RecommendBySenderRequestDTO; +import com.tikitaka.naechinso.domain.recommend.dto.RecommendResponseDTO; +import com.tikitaka.naechinso.global.config.CommonApiResponse; +import io.swagger.annotations.ApiOperation; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; + +/** + * 프론트에서 테스트를 원할하게 진행하기 위한 컨트롤러 + * QA 진행 후 삭제합니다 + * */ +@Slf4j +@RestController +@RequiredArgsConstructor +@RequestMapping("/test") +public class TestController { + private final MemberService memberService; + private final RecommendService recommendService; + private final PendingService pendingService; + + @GetMapping("/request-member") + @ApiOperation(value = "[*TEST*] 추천사를 요청하는 유저를 생성하고 엑세스 토큰을 반환한다") + public CommonApiResponse generateRecommendRequestUser( + ) { + MemberCommonJoinResponseDTO responseDTO = memberService.joinCommonMember( + "01012345678", + MemberCommonJoinRequestDTO.builder() + .age(25) + .gender(Gender.M) + .name("닉") + .acceptsInfo(true) + .acceptsLocation(true) + .acceptsMarketing(true) + .acceptsReligion(true) + .acceptsService(true) + .build()); + + Member member = memberService.findByPhone(responseDTO.getPhone()); + recommendService.createRecommendRequest(member); + + return CommonApiResponse.of(responseDTO); + } + + @GetMapping("/recommend-send") + @ApiOperation(value = "[*TEST*] 추천사를 요청하는 유저를 생성하고 엑세스 토큰을 반환한다") + public CommonApiResponse generateRecommendReceiver( + ) { + + //sender + MemberCommonJoinResponseDTO senderDTO = memberService.joinCommonMember( + "01011112222", + MemberCommonJoinRequestDTO.builder() + .age(25) + .gender(Gender.M) + .name("닉") + .acceptsInfo(true) + .acceptsLocation(true) + .acceptsMarketing(true) + .acceptsReligion(true) + .acceptsService(true) + .build()); + + Member sender = memberService.findByPhone(senderDTO.getPhone()); + + //sender + MemberCommonJoinResponseDTO receiverDTO = memberService.joinCommonMember( + "01012345678", + MemberCommonJoinRequestDTO.builder() + .age(25) + .gender(Gender.M) + .name("닉") + .acceptsInfo(true) + .acceptsLocation(true) + .acceptsMarketing(true) + .acceptsReligion(true) + .acceptsService(true) + .build()); + + RecommendResponseDTO recommend = recommendService.createRecommend(sender, RecommendBySenderRequestDTO + .builder() + .age(25) + .period("1년") + .appeal("짱") + .phone("01012345678") + .meet("CMC에서") + .personality("최고") + .gender(Gender.M) + .name("닉") + .build()); + + + return CommonApiResponse.of(receiverDTO); + } + + + @GetMapping("/create-job-pending") + @ApiOperation(value = "[*TEST*] 직업 업데이트 요청하는 멤버를 생성하고 엑세스 토큰을 반환한다") + public CommonApiResponse createJobPendingMember( + ) { + MemberCommonJoinResponseDTO responseDTO = memberService.joinCommonMember( + "01012345678", + MemberCommonJoinRequestDTO.builder() + .age(25) + .gender(Gender.M) + .name("닉") + .acceptsInfo(true) + .acceptsLocation(true) + .acceptsMarketing(true) + .acceptsReligion(true) + .acceptsService(true) + .build()); + Member member = memberService.findByPhone(responseDTO.getPhone()); + + pendingService.createPendingByJob(member, MemberUpdateJobRequestDTO.builder() + .jobName("직장명").jobPart("개발자").jobLocation("강남").jobImage("img1").build()); + + return CommonApiResponse.of(responseDTO); + + } + + + @GetMapping("/create-job-pending-and-recommend-other") + @ApiOperation(value = "[*TEST*] 직업 업데이트 요청하는 멤버를 생성하고 유저 한명을 추천한 뒤 다른 유저의 엑세스 토큰을 반환한다") + public CommonApiResponse createJobPendingMemberAndRecommendOther( + ) { + MemberCommonJoinResponseDTO senderDTO = memberService.joinCommonMember( + "01012345678", + MemberCommonJoinRequestDTO.builder() + .age(25) + .gender(Gender.M) + .name("닉") + .acceptsInfo(true) + .acceptsLocation(true) + .acceptsMarketing(true) + .acceptsReligion(true) + .acceptsService(true) + .build()); + Member member1 = memberService.findByPhone(senderDTO.getPhone()); + + pendingService.createPendingByJob(member1, MemberUpdateJobRequestDTO.builder() + .jobName("직장명").jobPart("개발자").jobLocation("강남").jobImage("img1").build()); + + MemberCommonJoinResponseDTO receiverDTO = memberService.joinCommonMember( + "01011111111", + MemberCommonJoinRequestDTO.builder() + .age(25) + .gender(Gender.M) + .name("닉") + .acceptsInfo(true) + .acceptsLocation(true) + .acceptsMarketing(true) + .acceptsReligion(true) + .acceptsService(true) + .build()); + Member member2 = memberService.findByPhone(receiverDTO.getPhone()); + + System.out.println("recommend = " + recommendService.createRecommend(member1, RecommendBySenderRequestDTO + .builder() + .age(25) + .period("1년") + .appeal("짱") + .phone("01011111111") + .meet("CMC에서") + .personality("최고") + .gender(Gender.M) + .name("닉") + .build())); + + return CommonApiResponse.of(receiverDTO); + + } +// +// @GetMapping("/create-detail-member") +// @ApiOperation(value = "[*TEST*] 추천사를 요청하는 유저를 생성하고 엑세스 토큰을 반환한다") +// public CommonApiResponse createDetailMember( +// ) { +// MemberCommonJoinResponseDTO responseDTO = memberService.joinCommonMember( +// "01012345678", +// MemberCommonJoinRequestDTO.builder() +// .age(25) +// .gender(Gender.M) +// .name("닉") +// .acceptsInfo(true) +// .acceptsLocation(true) +// .acceptsMarketing(true) +// .acceptsReligion(true) +// .acceptsService(true) +// .build()); +// Member member = memberService.findByPhone(responseDTO.getPhone()); +// +// return CommonApiResponse.of(memberService.createDetail(member, MemberDetailJoinRequestDTO.builder() +// .height(180) +// .address("우리집") +// .religion("무교") +// .drink("자주마심") +// .smoke("비흡연자") +// .mbti("ESTJ") +// .personality("짱좋음") +// .introduce("방갑습니다") +// .hobby("기타") +// .style("짱좋음") +// .images(List.of("img1, img2, img3")) +// .build())); +// +// } +} diff --git a/src/main/java/com/tikitaka/naechinso/domain/member/MemberController.java b/src/main/java/com/tikitaka/naechinso/domain/member/MemberController.java index 8328903..134fe52 100644 --- a/src/main/java/com/tikitaka/naechinso/domain/member/MemberController.java +++ b/src/main/java/com/tikitaka/naechinso/domain/member/MemberController.java @@ -2,6 +2,7 @@ import com.tikitaka.naechinso.domain.member.dto.*; import com.tikitaka.naechinso.domain.member.entity.Member; +import com.tikitaka.naechinso.domain.pending.dto.PendingFindResponseDTO; import com.tikitaka.naechinso.domain.recommend.RecommendService; import com.tikitaka.naechinso.global.annotation.AuthMember; import com.tikitaka.naechinso.global.config.CommonApiResponse; @@ -9,6 +10,7 @@ import io.swagger.annotations.ApiOperation; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; +import org.springframework.transaction.annotation.Transactional; import org.springframework.web.bind.annotation.*; import springfox.documentation.annotations.ApiIgnore; @@ -32,7 +34,7 @@ public class MemberController { public CommonApiResponse getMyInformation( @ApiIgnore @AuthMember Member member ) { - return CommonApiResponse.of(MemberCommonResponseDTO.of(member)); + return CommonApiResponse.of(memberService.readCommonMember(member)); } @GetMapping("/detail") @@ -74,26 +76,26 @@ public CommonApiResponse updateCommonMember( } @PatchMapping("/job") - @ApiOperation(value = "직업 정보를 업데이트 한다 (AccessToken)") - public CommonApiResponse updateJob( + @ApiOperation(value = "직업 인증 정보 업데이트 요청을 보낸다 (AccessToken)") + public CommonApiResponse updateJob( @Valid @RequestBody MemberUpdateJobRequestDTO dto, @ApiIgnore @AuthMember Member member ) { - return CommonApiResponse.of(memberService.updateJob(member, dto)); + return CommonApiResponse.of(memberService.updateJobRequest(member, dto)); } @PatchMapping("/edu") - @ApiOperation(value = "학력 정보를 업데이트 한다 (AccessToken)") - public CommonApiResponse updateEdu( + @ApiOperation(value = "학력 정보 업데이트 요청을 보낸다 (AccessToken)") + public CommonApiResponse updateEdu( @Valid @RequestBody MemberUpdateEduRequestDTO dto, @ApiIgnore @AuthMember Member member ) { - return CommonApiResponse.of(memberService.updateEdu(member, dto)); + return CommonApiResponse.of(memberService.updateEduRequest(member, dto)); } @PatchMapping("/image") @ApiOperation(value = "프로필 이미지를 업데이트 한다 (AccessToken)") - public CommonApiResponse updateImage( + public CommonApiResponse updateImage( @Valid @RequestBody MemberUpdateImageRequestDTO dto, @ApiIgnore @AuthMember Member member ) { diff --git a/src/main/java/com/tikitaka/naechinso/domain/member/MemberService.java b/src/main/java/com/tikitaka/naechinso/domain/member/MemberService.java index 59d6b84..aae5b47 100644 --- a/src/main/java/com/tikitaka/naechinso/domain/member/MemberService.java +++ b/src/main/java/com/tikitaka/naechinso/domain/member/MemberService.java @@ -5,8 +5,9 @@ import com.tikitaka.naechinso.domain.member.entity.MemberDetail; import com.tikitaka.naechinso.domain.pending.PendingService; import com.tikitaka.naechinso.domain.pending.constant.PendingType; -import com.tikitaka.naechinso.domain.pending.dto.PendingUpdateCreditImageRequestDTO; +import com.tikitaka.naechinso.domain.pending.dto.PendingFindResponseDTO; import com.tikitaka.naechinso.domain.pending.dto.PendingUpdateMemberImageRequestDTO; +import com.tikitaka.naechinso.domain.recommend.entity.Recommend; import com.tikitaka.naechinso.global.common.response.TokenResponseDTO; import com.tikitaka.naechinso.global.config.security.dto.JwtDTO; import com.tikitaka.naechinso.global.config.security.jwt.JwtTokenProvider; @@ -47,6 +48,10 @@ public List findAll() { .map(MemberFindResponseDTO::of).collect(Collectors.toList()); } + public MemberCommonResponseDTO readCommonMember(Member authMember) { + Member member = findByMember(authMember); + return MemberCommonResponseDTO.of(member); + } public MemberCommonJoinResponseDTO joinCommonMember(String phone, MemberCommonJoinRequestDTO dto) { //이미 존재하는 유저일 경우 400 @@ -93,56 +98,58 @@ public MemberDetailResponseDTO createDetail(Member authMember, MemberDetailJoinR } //추천 받은 정보가 없는 회원 - if (member.getRecommendReceived().isEmpty()) { + if (member.getRecommendReceived() == null || member.getRecommendReceived().isEmpty()) { throw new ForbiddenException(ErrorCode.RECOMMEND_NOT_RECEIVED); } - MemberDetail detail = MemberDetail.of(member, dto); - - - memberDetailRepository.save(detail); - return MemberDetailResponseDTO.of(detail); + for (Recommend recommend : member.getRecommendReceived()) { + //아직 추천인이 없는 상태면 무시 + if (recommend.getSender() == null) { + continue; + } + + //받은 추천사 중 한명이라도 인증이 완료된 상태면 정회원 가입 실행 + if (recommend.getSender().getJobAccepted() || recommend.getSender().getEduAccepted()) { + MemberDetail detail = MemberDetail.of(member, dto); + memberDetailRepository.save(detail); + + member.setDetail(detail); + pendingService.createPendingByMemberImage(member, new MemberUpdateImageRequestDTO(dto.getImages())); + return MemberDetailResponseDTO.of(detail); + } + } + //추천서를 작성한 사람의 인증이 완료되지 않은 경우 + throw new UnauthorizedException(ErrorCode.RECOMMEND_SENDER_UNAUTHORIZED); } - public MemberCommonResponseDTO updateJob(Member authMember, MemberUpdateJobRequestDTO dto){ - //영속성 유지를 위한 fetch - Member member = findByMember(authMember); - member.updateJob(dto); - memberRepository.save(member); + /** + * 직업 정보 업데이트 요청 처리 + * 사진 필드는 Pending 에서 승인 후 처리한다 + * */ + public PendingFindResponseDTO updateJobRequest(Member authMember, MemberUpdateJobRequestDTO dto){ +// member.updateJob(dto); +// memberRepository.save(member); //직업 정보 승인 요청 - pendingService.createPendingByCreditImage(new PendingUpdateCreditImageRequestDTO(member.getId(), PendingType.JOB, dto.getJobImage())); - return MemberCommonResponseDTO.of(member); + return pendingService.createPendingByJob(authMember, dto); } - public MemberCommonResponseDTO updateEdu(Member authMember, MemberUpdateEduRequestDTO dto){ - //영속성 유지를 위한 fetch - Member member = findByMember(authMember); - - member.updateEdu(dto); - memberRepository.save(member); - - //직업 정보 승인 요청 - pendingService.createPendingByCreditImage(new PendingUpdateCreditImageRequestDTO(member.getId(), PendingType.EDU, dto.getEduImage())); - - return MemberCommonResponseDTO.of(member); + /** + * 학력 정보 업데이트 요청 처리 + * 사진 필드는 Pending 에서 승인 후 처리한다 + * */ + public PendingFindResponseDTO updateEduRequest(Member authMember, MemberUpdateEduRequestDTO dto){ + //학력 정보 승인 요청 + return pendingService.createPendingByEdu(authMember, dto); } /** * MemberDetail 의 프로필 이미지를 업로드 한다 * */ - public MemberDetailResponseDTO updateImage(Member authMember, MemberUpdateImageRequestDTO dto){ - //영속성 유지를 위한 fetch - Member member = findByMember(authMember); - member.updateImage(dto.getImages()); - - //프로필 사진 정보 승인 요청 - pendingService.createPendingByMemberImage(new PendingUpdateMemberImageRequestDTO(member.getId(), PendingType.EDU, dto.getImages())); - - memberRepository.save(member); - return MemberDetailResponseDTO.of(member); + public PendingFindResponseDTO updateImage(Member authMember, MemberUpdateImageRequestDTO dto){ + return pendingService.createPendingByMemberImage(authMember, dto); } diff --git a/src/main/java/com/tikitaka/naechinso/domain/member/dto/MemberCommonResponseDTO.java b/src/main/java/com/tikitaka/naechinso/domain/member/dto/MemberCommonResponseDTO.java index e5881cb..a15927b 100644 --- a/src/main/java/com/tikitaka/naechinso/domain/member/dto/MemberCommonResponseDTO.java +++ b/src/main/java/com/tikitaka/naechinso/domain/member/dto/MemberCommonResponseDTO.java @@ -3,11 +3,15 @@ import com.tikitaka.naechinso.domain.member.constant.Gender; import com.tikitaka.naechinso.domain.member.constant.Role; import com.tikitaka.naechinso.domain.member.entity.Member; +import com.tikitaka.naechinso.domain.pending.dto.PendingFindResponseDTO; +import com.tikitaka.naechinso.domain.pending.entity.Pending; import io.swagger.annotations.ApiModelProperty; import lombok.*; import javax.persistence.Column; import javax.validation.constraints.NotBlank; +import java.util.List; +import java.util.stream.Collectors; /** * 추천인 및 추천 받는 사람 공통 가입을 위한 Dto입니다 @@ -38,6 +42,8 @@ public class MemberCommonResponseDTO { private String jobImage; + private Boolean jobAccepted; + private String eduName; private String eduMajor; @@ -46,9 +52,10 @@ public class MemberCommonResponseDTO { private String eduImage; + private Boolean eduAccepted; public static MemberCommonResponseDTO of(Member member) { - MemberCommonResponseDTO res = MemberCommonResponseDTO.builder() + return MemberCommonResponseDTO.builder() .phone(member.getPhone()) .role(member.getRole()) .name(member.getName()) @@ -58,12 +65,12 @@ public static MemberCommonResponseDTO of(Member member) { .jobPart(member.getJobPart()) .jobLocation(member.getJobLocation()) .jobImage(member.getJobImage()) + .jobAccepted(member.getJobAccepted()) .eduName(member.getEduName()) .eduMajor(member.getEduMajor()) .eduLevel(member.getEduLevel()) .eduImage(member.getEduImage()) + .eduAccepted(member.getEduAccepted()) .build(); - - return res; } } diff --git a/src/main/java/com/tikitaka/naechinso/domain/member/dto/MemberUpdateEduRequestDTO.java b/src/main/java/com/tikitaka/naechinso/domain/member/dto/MemberUpdateEduRequestDTO.java index 8822f0d..47c1614 100644 --- a/src/main/java/com/tikitaka/naechinso/domain/member/dto/MemberUpdateEduRequestDTO.java +++ b/src/main/java/com/tikitaka/naechinso/domain/member/dto/MemberUpdateEduRequestDTO.java @@ -1,9 +1,14 @@ package com.tikitaka.naechinso.domain.member.dto; +import com.tikitaka.naechinso.global.error.ErrorCode; +import com.tikitaka.naechinso.global.error.exception.BadRequestException; import io.swagger.annotations.ApiModelProperty; import lombok.*; +import org.apache.tomcat.util.json.JSONParser; +import org.json.JSONObject; import javax.validation.constraints.NotBlank; +import java.util.List; /** * 직업 정보 업데이트를 위한 DTO @@ -30,4 +35,22 @@ public class MemberUpdateEduRequestDTO { @ApiModelProperty(example = "인증 사진 링크") @NotBlank(message = "인증 사진을 업로드 해주세요") private String eduImage; + + public static MemberUpdateEduRequestDTO of(String content) { + JSONObject json = new JSONObject(content); + try { + final String eduName = json.getString("eduName"); + final String eduMajor = json.getString("eduMajor"); + final String eduLevel = json.getString("eduLevel"); + final String eduImage = json.getString("eduImage"); + return MemberUpdateEduRequestDTO.builder() + .eduName(eduName) + .eduMajor(eduMajor) + .eduLevel(eduLevel) + .eduImage(eduImage) + .build(); + } catch (Exception e) { + throw new BadRequestException(ErrorCode._BAD_REQUEST, "JSON 형식 오류입니다"); + } + } } diff --git a/src/main/java/com/tikitaka/naechinso/domain/member/dto/MemberUpdateImageRequestDTO.java b/src/main/java/com/tikitaka/naechinso/domain/member/dto/MemberUpdateImageRequestDTO.java index 17d7aae..9c24b3c 100644 --- a/src/main/java/com/tikitaka/naechinso/domain/member/dto/MemberUpdateImageRequestDTO.java +++ b/src/main/java/com/tikitaka/naechinso/domain/member/dto/MemberUpdateImageRequestDTO.java @@ -22,4 +22,8 @@ public class MemberUpdateImageRequestDTO { @Size(min = 3, max = 3, message = "사진 3장을 업로드해야 합니다") @NotNull private List images; + + public static MemberUpdateImageRequestDTO of(List images) { + return new MemberUpdateImageRequestDTO(images); + } } diff --git a/src/main/java/com/tikitaka/naechinso/domain/member/dto/MemberUpdateJobRequestDTO.java b/src/main/java/com/tikitaka/naechinso/domain/member/dto/MemberUpdateJobRequestDTO.java index 36444bd..42d5363 100644 --- a/src/main/java/com/tikitaka/naechinso/domain/member/dto/MemberUpdateJobRequestDTO.java +++ b/src/main/java/com/tikitaka/naechinso/domain/member/dto/MemberUpdateJobRequestDTO.java @@ -1,9 +1,13 @@ package com.tikitaka.naechinso.domain.member.dto; +import com.tikitaka.naechinso.global.error.ErrorCode; +import com.tikitaka.naechinso.global.error.exception.BadRequestException; import io.swagger.annotations.ApiModelProperty; import lombok.*; +import org.json.JSONObject; import javax.validation.constraints.NotBlank; +import java.util.List; /** * 직업 정보 업데이트를 위한 DTO @@ -30,4 +34,22 @@ public class MemberUpdateJobRequestDTO { @ApiModelProperty(example = "인증 사진 링크") @NotBlank(message = "인증 사진을 업로드 해주세요") private String jobImage; + + public static MemberUpdateJobRequestDTO of(String content) { + JSONObject json = new JSONObject(content); + try { + final String jobName = json.getString("jobName"); + final String jobLocation = json.getString("jobLocation"); + final String jobPart = json.getString("jobPart"); + final String jobImage = json.getString("jobImage"); + return MemberUpdateJobRequestDTO.builder() + .jobName(jobName) + .jobPart(jobPart) + .jobLocation(jobLocation) + .jobImage(jobImage) + .build(); + } catch (Exception e) { + throw new BadRequestException(ErrorCode._BAD_REQUEST, "JSON 형식 오류입니다"); + } + } } diff --git a/src/main/java/com/tikitaka/naechinso/domain/member/entity/Member.java b/src/main/java/com/tikitaka/naechinso/domain/member/entity/Member.java index 6c615f8..ccade95 100644 --- a/src/main/java/com/tikitaka/naechinso/domain/member/entity/Member.java +++ b/src/main/java/com/tikitaka/naechinso/domain/member/entity/Member.java @@ -87,7 +87,8 @@ public class Member extends BaseEntity { private String jobImage; @Column(name = "mem_job_accepted") - private Boolean jobAccepted; + @Builder.Default + private Boolean jobAccepted = false; @Column(name = "mem_edu_school") private String eduName; @@ -102,10 +103,12 @@ public class Member extends BaseEntity { private String eduImage; @Column(name = "mem_edu_accepted") - private Boolean eduAccepted; + @Builder.Default + private Boolean eduAccepted = false; @Column(name = "mem_join_accepted") - private Boolean joinAccepted; + @Builder.Default + private Boolean joinAccepted = false; //멤버 디테일 정보 @OneToOne(mappedBy = "member") @@ -139,6 +142,8 @@ public void updateJob(MemberUpdateJobRequestDTO requestDTO) { this.jobLocation = requestDTO.getJobLocation(); this.jobPart = requestDTO.getJobPart(); this.jobImage = requestDTO.getJobImage(); + + this.jobAccepted = true; } public void updateEdu(MemberUpdateEduRequestDTO requestDTO) { @@ -146,6 +151,8 @@ public void updateEdu(MemberUpdateEduRequestDTO requestDTO) { this.eduMajor = requestDTO.getEduMajor(); this.eduLevel = requestDTO.getEduLevel(); this.eduImage = requestDTO.getEduImage(); + + this.eduAccepted = true; } public void updateCommon(MemberUpdateCommonRequestDTO dto) { diff --git a/src/main/java/com/tikitaka/naechinso/domain/member/entity/MemberDetail.java b/src/main/java/com/tikitaka/naechinso/domain/member/entity/MemberDetail.java index e4c786e..c1b6689 100644 --- a/src/main/java/com/tikitaka/naechinso/domain/member/entity/MemberDetail.java +++ b/src/main/java/com/tikitaka/naechinso/domain/member/entity/MemberDetail.java @@ -72,6 +72,9 @@ public class MemberDetail extends BaseEntity { @Column(name = "mem_images") private String images; + @Column(name = "mem_image_accepted") + private Boolean image_accepted; + @Column(name = "mem_point") @Builder.Default private Long point = 0L; @@ -118,16 +121,20 @@ public static MemberDetail of(Member member, MemberDetailJoinRequestDTO dto) { .introduce(dto.getIntroduce()) .hobby(dto.getHobby()) .style(dto.getStyle()) - .images(StringUtils.join(dto.getImages(), ",")) +// .images(StringUtils.join(dto.getImages(), ",")) // image pending .member(member) .build(); } public List getImages() { - return List.of(this.images.split(",")); + if (this.images != null) { + return List.of(this.images.split(",")); + } + return List.of(); } public List updateImage(List images) { this.images = StringUtils.join(images, ","); + this.image_accepted = true; return images; } } diff --git a/src/main/java/com/tikitaka/naechinso/domain/pending/PendingController.java b/src/main/java/com/tikitaka/naechinso/domain/pending/PendingController.java index 47d75f5..c0b1c95 100644 --- a/src/main/java/com/tikitaka/naechinso/domain/pending/PendingController.java +++ b/src/main/java/com/tikitaka/naechinso/domain/pending/PendingController.java @@ -3,11 +3,13 @@ import com.tikitaka.naechinso.domain.member.entity.Member; import com.tikitaka.naechinso.domain.pending.dto.PendingRejectRequestDTO; import com.tikitaka.naechinso.domain.pending.dto.PendingFindResponseDTO; +import com.tikitaka.naechinso.global.annotation.AuthMember; import com.tikitaka.naechinso.global.config.CommonApiResponse; import io.swagger.annotations.ApiOperation; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; import org.springframework.web.bind.annotation.*; +import springfox.documentation.annotations.ApiIgnore; import java.util.List; @@ -21,23 +23,22 @@ public class PendingController { private final PendingService pendingService; @GetMapping - @ApiOperation(value = "[Admin]모든 가입 대기 정보를 가져온다 (AccessToken)") - public CommonApiResponse> getAllPending( -// @ApiIgnore @AuthMember Member member + @ApiOperation(value = "내 승인 대기 정보를 가져온다 (AccessToken)") + public CommonApiResponse> getPendingByMember( + @ApiIgnore @AuthMember Member member ) { - return CommonApiResponse.of(pendingService.findAll()); + return CommonApiResponse.of(pendingService.findAllByMemberId(member.getId())); } - @PostMapping - @ApiOperation(value = "[테스트]가입 대기 정보 생성 (AccessToken)") - public CommonApiResponse> createPending( - @RequestBody PendingRejectRequestDTO dto + @GetMapping("/find") + @ApiOperation(value = "[Admin]모든 가입 대기 정보를 가져온다 (AccessToken)") + public CommonApiResponse> getAllPending( // @ApiIgnore @AuthMember Member member ) { - return CommonApiResponse.of(pendingService.findAll()); } + @PostMapping("/accept/{id}") @ApiOperation(value = "[테스트]요청을 승인한다 (AccessToken)") public CommonApiResponse acceptPending( diff --git a/src/main/java/com/tikitaka/naechinso/domain/pending/PendingRepository.java b/src/main/java/com/tikitaka/naechinso/domain/pending/PendingRepository.java index 427380c..48a19a3 100644 --- a/src/main/java/com/tikitaka/naechinso/domain/pending/PendingRepository.java +++ b/src/main/java/com/tikitaka/naechinso/domain/pending/PendingRepository.java @@ -11,4 +11,5 @@ public interface PendingRepository extends JpaRepository { List findAllByMemberId(Long memberId); List findAllByMemberIdAndIsAcceptedIsTrue(Long memberId); + } diff --git a/src/main/java/com/tikitaka/naechinso/domain/pending/PendingService.java b/src/main/java/com/tikitaka/naechinso/domain/pending/PendingService.java index 74ba2e6..85d3775 100644 --- a/src/main/java/com/tikitaka/naechinso/domain/pending/PendingService.java +++ b/src/main/java/com/tikitaka/naechinso/domain/pending/PendingService.java @@ -1,16 +1,23 @@ package com.tikitaka.naechinso.domain.pending; +import com.fasterxml.jackson.databind.ObjectMapper; import com.tikitaka.naechinso.domain.member.MemberRepository; +import com.tikitaka.naechinso.domain.member.dto.MemberUpdateEduRequestDTO; +import com.tikitaka.naechinso.domain.member.dto.MemberUpdateImageRequestDTO; +import com.tikitaka.naechinso.domain.member.dto.MemberUpdateJobRequestDTO; import com.tikitaka.naechinso.domain.member.entity.Member; +import com.tikitaka.naechinso.domain.pending.constant.PendingType; import com.tikitaka.naechinso.domain.pending.dto.PendingFindResponseDTO; -import com.tikitaka.naechinso.domain.pending.dto.PendingUpdateCreditImageRequestDTO; import com.tikitaka.naechinso.domain.pending.dto.PendingUpdateMemberImageRequestDTO; import com.tikitaka.naechinso.domain.pending.entity.Pending; import com.tikitaka.naechinso.global.error.ErrorCode; import com.tikitaka.naechinso.global.error.exception.BadRequestException; +import com.tikitaka.naechinso.global.error.exception.ForbiddenException; import com.tikitaka.naechinso.global.error.exception.NotFoundException; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; +import org.apache.commons.lang3.StringUtils; +import org.json.JSONObject; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; @@ -26,54 +33,137 @@ public class PendingService { private final MemberRepository memberRepository; private final PendingRepository pendingRepository; + + +// /** +// * 학력 인증 정보 검토를 요청한다 +// * */ +// public PendingFindResponseDTO readPendingByMember(Member authMember) { +// //영속성 컨텍스트 가져오기 +// Member member = memberRepository.findById(authMember.getId()) +// .orElseThrow(() -> new NotFoundException(ErrorCode.USER_NOT_FOUND)); +// +// return findAllByMemberId(member.getId()); +// } + + /** - * 직장이나 학력 인증 정보 승인을 요청한다 + * 학력 인증 정보 검토를 요청한다 * */ - public PendingFindResponseDTO createPendingByCreditImage(PendingUpdateCreditImageRequestDTO dto) { + public PendingFindResponseDTO createPendingByEdu(Member authMember, MemberUpdateEduRequestDTO dto) { //영속성 컨텍스트 가져오기 - Member member = memberRepository.findById(dto.getMemberId()) + Member member = memberRepository.findById(authMember.getId()) .orElseThrow(() -> new NotFoundException(ErrorCode.USER_NOT_FOUND)); + //이미 심사중인 요청이 있음 + if (member.getPending() != null) { + member.getPending().forEach(pending -> { + if (pending.getType() == PendingType.EDU && pending.getAdminId() == null) + throw new BadRequestException(ErrorCode.DUPLICATE_PENDING_REQUEST); + }); + } + Pending pending = Pending.builder() .member(member) - .type(dto.getType()) - .images(dto.getImages()) + .type(PendingType.EDU) + .content(new JSONObject(dto).toString()) + .images(dto.getEduImage()) .build(); pendingRepository.save(pending); return PendingFindResponseDTO.of(pending); } + /** - * 유저의 프로필 사진 승인을 요청한다 + * 직장 인증 정보 검토를 요청한다 * */ - public PendingFindResponseDTO createPendingByMemberImage(PendingUpdateMemberImageRequestDTO dto) { + public PendingFindResponseDTO createPendingByJob(Member authMember, MemberUpdateJobRequestDTO dto) { //영속성 컨텍스트 가져오기 - Member member = memberRepository.findById(dto.getMemberId()) + Member member = memberRepository.findById(authMember.getId()) .orElseThrow(() -> new NotFoundException(ErrorCode.USER_NOT_FOUND)); + //이미 심사중인 요청이 있음 + if (member.getPending() != null) { + member.getPending().forEach(pending -> { + if (pending.getType() == PendingType.JOB && pending.getAdminId() == null) + throw new BadRequestException(ErrorCode.DUPLICATE_PENDING_REQUEST); + }); + } + Pending pending = Pending.builder() .member(member) - .type(dto.getType()) + .type(PendingType.JOB) + .content(new JSONObject(dto).toString()) + .images(dto.getJobImage()) .build(); - pending.updateImage(dto.getImages()); pendingRepository.save(pending); return PendingFindResponseDTO.of(pending); } /** - * 유저의 요청을 승인한다 + * 유저의 프로필 사진 검토를 요청한다 + * */ + public PendingFindResponseDTO createPendingByMemberImage(Member authMember, MemberUpdateImageRequestDTO dto) { + //영속성 컨텍스트 가져오기 + Member member = memberRepository.findById(authMember.getId()) + .orElseThrow(() -> new NotFoundException(ErrorCode.USER_NOT_FOUND)); + + //MemberDetail 이 없음. 정회원이 아님 + if (member.getDetail() == null) { + throw new ForbiddenException(ErrorCode.FORBIDDEN_USER); + } + + //이미 심사중인 요청이 있음 + if (member.getPending() != null) { + member.getPending().forEach(pending -> { + if (pending.getType() == PendingType.MEMBER && pending.getAdminId() == null) + throw new BadRequestException(ErrorCode.DUPLICATE_PENDING_REQUEST); + }); + } + + Pending pending = Pending.builder() + .member(member) + .type(PendingType.MEMBER) + .images(StringUtils.join(dto.getImages(), ",")) + .build(); + + pendingRepository.save(pending); + return PendingFindResponseDTO.of(pending); + } + + /** + * 유저의 요청을 승인하고 정보를 업데이트 한다 * */ public PendingFindResponseDTO acceptPending(Member adminMember, Long pendingId) { Pending pending = pendingRepository.findById(pendingId) .orElseThrow(() -> new NotFoundException(ErrorCode._BAD_REQUEST)); + Member pendingMember = pending.getMember(); //유저 정보가 없는 가입 승인 요청 - if (pending.getMember() == null) { + if (pendingMember == null) { throw new BadRequestException(ErrorCode.USER_NOT_FOUND); } + //어드민 유저가 아니면 접근 거부 +// if (adminMember.getRole().getDetail() != "ROLE_ADMIN") { +// throw new UnauthorizedException(ErrorCode.UNAUTHORIZED_USER); +// } + + //승인 하면 멤버의 인증 정보 또는 사진이 변경됨 + if (pending.getType() == PendingType.JOB) { + MemberUpdateJobRequestDTO requestDTO = pending.getJobContent(); + pendingMember.updateJob(requestDTO); + } + else if (pending.getType() == PendingType.EDU) { + MemberUpdateEduRequestDTO requestDTO = pending.getEduContent(); + pendingMember.updateEdu(requestDTO); + } + else if (pending.getType() == PendingType.MEMBER) { + pendingMember.updateImage(pending.getImages()); + } + pending.accept(adminMember); pendingRepository.save(pending); diff --git a/src/main/java/com/tikitaka/naechinso/domain/pending/dto/PendingFindResponseDTO.java b/src/main/java/com/tikitaka/naechinso/domain/pending/dto/PendingFindResponseDTO.java index a8e586b..6f0f98a 100644 --- a/src/main/java/com/tikitaka/naechinso/domain/pending/dto/PendingFindResponseDTO.java +++ b/src/main/java/com/tikitaka/naechinso/domain/pending/dto/PendingFindResponseDTO.java @@ -1,11 +1,16 @@ package com.tikitaka.naechinso.domain.pending.dto; +import com.fasterxml.jackson.annotation.JsonProperty; import com.tikitaka.naechinso.domain.pending.constant.PendingType; import com.tikitaka.naechinso.domain.pending.entity.Pending; import lombok.*; +import org.json.JSONObject; +import org.springframework.security.core.parameters.P; import java.time.LocalDateTime; +import java.time.format.DateTimeFormatter; import java.util.List; +import java.util.Map; @AllArgsConstructor @NoArgsConstructor @@ -22,33 +27,42 @@ public class PendingFindResponseDTO { private PendingType type; + private Map content; + private Boolean isAccepted; private String reason; private List images; - - private LocalDateTime createdAt; + private String createdAt; public static PendingFindResponseDTO of(Pending pending) { Long memberId; + Map content; if (pending.getMember() == null) { memberId = null; } else { memberId = pending.getMember().getId(); } + if (pending.getContent() != null) { + content = new JSONObject(pending.getContent()).toMap(); + } else { + content = null; + } + return PendingFindResponseDTO.builder() .id(pending.getId()) .memberId(memberId) .type(pending.getType()) + .content(content) .isAccepted(pending.getIsAccepted()) .reason(pending.getReason()) .images(pending.getImages()) .adminId(pending.getAdminId()) - .createdAt(pending.getCreatedAt()) + .createdAt(pending.getCreatedAt().toString()) .build(); } } diff --git a/src/main/java/com/tikitaka/naechinso/domain/pending/dto/PendingResponseDTO.java b/src/main/java/com/tikitaka/naechinso/domain/pending/dto/PendingResponseDTO.java index b5cdcbd..56a1da9 100644 --- a/src/main/java/com/tikitaka/naechinso/domain/pending/dto/PendingResponseDTO.java +++ b/src/main/java/com/tikitaka/naechinso/domain/pending/dto/PendingResponseDTO.java @@ -24,17 +24,17 @@ public class PendingResponseDTO { private Long adminId; - private LocalDateTime createdAt; + private String createdAt; - public static PendingFindResponseDTO of(Pending pending) { - return PendingFindResponseDTO.builder() + public static PendingResponseDTO of(Pending pending) { + return PendingResponseDTO.builder() .type(pending.getType()) .isAccepted(pending.getIsAccepted()) .reason(pending.getReason()) .images(pending.getImages()) .adminId(pending.getAdminId()) - .createdAt(pending.getCreatedAt()) + .createdAt(pending.getCreatedAt().toString()) .build(); } } diff --git a/src/main/java/com/tikitaka/naechinso/domain/pending/dto/PendingUpdateEduRequestDTO.java b/src/main/java/com/tikitaka/naechinso/domain/pending/dto/PendingUpdateEduRequestDTO.java new file mode 100644 index 0000000..1571bd9 --- /dev/null +++ b/src/main/java/com/tikitaka/naechinso/domain/pending/dto/PendingUpdateEduRequestDTO.java @@ -0,0 +1,39 @@ +package com.tikitaka.naechinso.domain.pending.dto; + +import com.tikitaka.naechinso.domain.member.dto.MemberUpdateEduRequestDTO; +import com.tikitaka.naechinso.domain.member.dto.MemberUpdateJobRequestDTO; +import com.tikitaka.naechinso.domain.pending.constant.PendingType; +import com.tikitaka.naechinso.global.annotation.Enum; +import io.swagger.annotations.ApiModelProperty; +import lombok.*; + +import javax.validation.constraints.NotEmpty; +import javax.validation.constraints.Positive; + +/** + * 유저의 직장 정보나 학교 인증 정보를 업데이트 할 때 + * 어드민의 승인을 받기 위한 Pending 엔티티 생성을 요청하는 DTO + * @author gengminy 221008 + * */ +@AllArgsConstructor +@NoArgsConstructor +@Getter +@Builder +@ToString +public class PendingUpdateEduRequestDTO { + @ApiModelProperty(example = "1") + @Positive(message = "올바르지 않은 id 형식입니다") + private Long memberId; + + @ApiModelProperty(example = "edu") + @Enum(enumClass = PendingType.class, message = "승인 요청 타입이 올바르지 않습니다") + private PendingType type; + + @ApiModelProperty + @NotEmpty + private MemberUpdateEduRequestDTO content; + + @ApiModelProperty(example = "img1") + @NotEmpty + private String image; +} diff --git a/src/main/java/com/tikitaka/naechinso/domain/pending/dto/PendingUpdateCreditImageRequestDTO.java b/src/main/java/com/tikitaka/naechinso/domain/pending/dto/PendingUpdateJobRequestDTO.java similarity index 79% rename from src/main/java/com/tikitaka/naechinso/domain/pending/dto/PendingUpdateCreditImageRequestDTO.java rename to src/main/java/com/tikitaka/naechinso/domain/pending/dto/PendingUpdateJobRequestDTO.java index 828adea..0cf2d24 100644 --- a/src/main/java/com/tikitaka/naechinso/domain/pending/dto/PendingUpdateCreditImageRequestDTO.java +++ b/src/main/java/com/tikitaka/naechinso/domain/pending/dto/PendingUpdateJobRequestDTO.java @@ -1,12 +1,12 @@ package com.tikitaka.naechinso.domain.pending.dto; +import com.tikitaka.naechinso.domain.member.dto.MemberUpdateJobRequestDTO; import com.tikitaka.naechinso.domain.pending.constant.PendingType; import com.tikitaka.naechinso.global.annotation.Enum; import io.swagger.annotations.ApiModelProperty; import lombok.*; import javax.validation.constraints.*; -import java.util.List; /** * 유저의 직장 정보나 학교 인증 정보를 업데이트 할 때 @@ -18,7 +18,7 @@ @Getter @Builder @ToString -public class PendingUpdateCreditImageRequestDTO { +public class PendingUpdateJobRequestDTO { @ApiModelProperty(example = "1") @Positive(message = "올바르지 않은 id 형식입니다") private Long memberId; @@ -27,7 +27,11 @@ public class PendingUpdateCreditImageRequestDTO { @Enum(enumClass = PendingType.class, message = "승인 요청 타입이 올바르지 않습니다") private PendingType type; + @ApiModelProperty + @NotEmpty + private MemberUpdateJobRequestDTO content; + @ApiModelProperty(example = "img1") @NotEmpty - private String images; + private String image; } diff --git a/src/main/java/com/tikitaka/naechinso/domain/pending/entity/Pending.java b/src/main/java/com/tikitaka/naechinso/domain/pending/entity/Pending.java index 0bfed08..a636dea 100644 --- a/src/main/java/com/tikitaka/naechinso/domain/pending/entity/Pending.java +++ b/src/main/java/com/tikitaka/naechinso/domain/pending/entity/Pending.java @@ -1,17 +1,16 @@ package com.tikitaka.naechinso.domain.pending.entity; import com.fasterxml.jackson.annotation.JsonIgnore; +import com.tikitaka.naechinso.domain.member.dto.MemberUpdateEduRequestDTO; +import com.tikitaka.naechinso.domain.member.dto.MemberUpdateJobRequestDTO; import com.tikitaka.naechinso.domain.member.entity.Member; import com.tikitaka.naechinso.domain.pending.constant.PendingType; import com.tikitaka.naechinso.global.config.entity.BaseEntity; -import com.tikitaka.naechinso.global.error.ErrorCode; -import com.tikitaka.naechinso.global.error.exception.UnauthorizedException; import lombok.*; import org.apache.commons.lang3.StringUtils; import javax.persistence.*; import java.util.List; -import java.util.Objects; @Entity @Table(name = "pending") @@ -35,8 +34,12 @@ public class Pending extends BaseEntity { private Member member; @Column(name = "pen_type") + @Enumerated(EnumType.STRING) private PendingType type; + @Column(name = "pen_content") + private String content; + @Column(name = "pen_is_accepted") @Builder.Default private Boolean isAccepted = false; @@ -61,11 +64,15 @@ public List updateImage(List images) { } public void accept(Member adminMember) { - //어드민이 아니면 거부 -// if (!Objects.equals(adminMember.getRole().getDetail(), "ROLE_ADMIN")) { -// throw new UnauthorizedException(ErrorCode.UNAUTHORIZED_USER); -// } this.isAccepted = true; this.adminId = adminMember.getId(); } + + public MemberUpdateEduRequestDTO getEduContent() { + return MemberUpdateEduRequestDTO.of(this.content); + } + + public MemberUpdateJobRequestDTO getJobContent() { + return MemberUpdateJobRequestDTO.of(this.content); + } } diff --git a/src/main/java/com/tikitaka/naechinso/domain/recommend/dto/RecommendReceiverDTO.java b/src/main/java/com/tikitaka/naechinso/domain/recommend/dto/RecommendReceiverDTO.java index 858aa4c..795e54a 100644 --- a/src/main/java/com/tikitaka/naechinso/domain/recommend/dto/RecommendReceiverDTO.java +++ b/src/main/java/com/tikitaka/naechinso/domain/recommend/dto/RecommendReceiverDTO.java @@ -2,6 +2,8 @@ import com.tikitaka.naechinso.domain.member.constant.Gender; import com.tikitaka.naechinso.domain.recommend.entity.Recommend; +import com.tikitaka.naechinso.global.error.ErrorCode; +import com.tikitaka.naechinso.global.error.exception.BadRequestException; import lombok.*; /** @@ -19,11 +21,18 @@ public class RecommendReceiverDTO { private int age; + //추천인의 사진 인증 승인 여부 + private boolean senderCreditAccepted; + public static RecommendReceiverDTO of(Recommend recommend) { + if (recommend.getSender() == null) { + throw new BadRequestException(ErrorCode.RECOMMEND_SENDER_NOT_EXIST); + } return RecommendReceiverDTO.builder() - .name(recommend.getReceiverName()) - .gender(recommend.getReceiverGender()) - .age(recommend.getReceiverAge()) + .name(recommend.getSenderName()) + .gender(recommend.getSenderGender()) + .age(recommend.getSenderAge()) + .senderCreditAccepted(recommend.getSender().getEduAccepted() || recommend.getSender().getJobAccepted() ) .build(); } } diff --git a/src/main/java/com/tikitaka/naechinso/global/config/security/SecurityConfig.java b/src/main/java/com/tikitaka/naechinso/global/config/security/SecurityConfig.java index d3897d3..2702588 100644 --- a/src/main/java/com/tikitaka/naechinso/global/config/security/SecurityConfig.java +++ b/src/main/java/com/tikitaka/naechinso/global/config/security/SecurityConfig.java @@ -59,7 +59,8 @@ public SecurityFilterChain filterChain(HttpSecurity http) throws Exception { .antMatchers(SwaggerPatterns).permitAll() .antMatchers(HttpMethod.DELETE,"/s3/image/**").hasAuthority("ROLE_ADMIN") .antMatchers("/admin/**").hasAuthority("ROLE_ADMIN") - .antMatchers("/pending/**").permitAll() ///////////////////////////////////////가입승인대기 + .antMatchers("/pending/find").permitAll() ///////////////////////////////////////가입승인대기 + .antMatchers("/test/**").permitAll() ///////////////////////////////////////테스트 .antMatchers("/member/join").permitAll() .antMatchers("/").permitAll() //health check .antMatchers("/sms/**").permitAll() diff --git a/src/main/java/com/tikitaka/naechinso/global/config/security/jwt/JwtTokenProvider.java b/src/main/java/com/tikitaka/naechinso/global/config/security/jwt/JwtTokenProvider.java index 9606600..37ab2ad 100644 --- a/src/main/java/com/tikitaka/naechinso/global/config/security/jwt/JwtTokenProvider.java +++ b/src/main/java/com/tikitaka/naechinso/global/config/security/jwt/JwtTokenProvider.java @@ -122,8 +122,6 @@ public String generateRegisterToken(JwtDTO jwtDTO) public Authentication getAuthentication(HttpServletRequest request, String accessToken) { Claims claims = parseClaims(accessToken); - System.out.println("claims = " + claims); // - if (claims.get(AUTHORITIES_KEY) == null) { request.setAttribute("exception", ErrorCode.INVALID_AUTH_TOKEN.getCode()); throw new UnauthorizedException(ErrorCode.INVALID_AUTH_TOKEN); diff --git a/src/main/java/com/tikitaka/naechinso/global/error/ErrorCode.java b/src/main/java/com/tikitaka/naechinso/global/error/ErrorCode.java index 9d68814..2342a05 100644 --- a/src/main/java/com/tikitaka/naechinso/global/error/ErrorCode.java +++ b/src/main/java/com/tikitaka/naechinso/global/error/ErrorCode.java @@ -48,6 +48,7 @@ public enum ErrorCode { USER_ALREADY_EXIST(BAD_REQUEST, "U002","이미 가입된 유저입니다"), USER_NOT_FOUND(NOT_FOUND, "U003","해당 유저 정보를 찾을 수 없습니다"), NOT_FOLLOW(NOT_FOUND, "U004","팔로우 중이지 않습니다"), + DUPLICATE_PENDING_REQUEST(NOT_FOUND, "U005","동일한 종류의 심사 요청은 한 번만 보낼 수 있습니다"), /* Recommend 관련 오류 */ @@ -58,6 +59,8 @@ public enum ErrorCode { RECOMMEND_RECEIVER_NOT_EXIST(BAD_REQUEST, "R004","추천 받을 사람이 존재하지 않습니다"), RECOMMEND_REQUEST_ALREADY_EXIST(BAD_REQUEST, "R005","추천사 요청은 한 번만 보낼 수 있습니다"), RECOMMEND_NOT_RECEIVED(FORBIDDEN, "R006","가입하기 위해서는 먼저 추천사를 받아야 합니다"), + RECOMMEND_SENDER_UNAUTHORIZED(UNAUTHORIZED, "R007","추천인의 인증이 아직 완료되지 않았습니다"), + RECOMMEND_SENDER_NOT_EXIST(BAD_REQUEST, "R008","추천인 정보가 올바르지 않습니다"), /* Validation 오류 */ PARAMETER_NOT_VALID(BAD_REQUEST, "P000", "인자가 유효하지 않습니다"), From 1348bbcad2f4d03986e1f6f8f43ae1c697dd0cab Mon Sep 17 00:00:00 2001 From: gengminy Date: Mon, 10 Oct 2022 20:38:43 +0900 Subject: [PATCH 24/72] =?UTF-8?q?:rocket:=20feat(pend):=20=EC=96=B4?= =?UTF-8?q?=EB=93=9C=EB=AF=BC=20=EC=9A=94=EC=B2=AD=20=EC=8A=B9=EC=9D=B8=20?= =?UTF-8?q?=EB=B0=8F=20=EA=B1=B0=EC=A0=88=20=EA=B5=AC=ED=98=84=20#37?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../naechinso/domain/TestController.java | 18 ++++++ .../domain/member/MemberController.java | 6 +- .../domain/member/MemberService.java | 6 +- .../member/dto/MemberFindResponseDTO.java | 4 +- .../member/dto/MemberUpdateEduRequestDTO.java | 4 +- .../domain/member/entity/Member.java | 16 ++++++ .../domain/pending/PendingController.java | 23 +++++--- .../domain/pending/PendingService.java | 57 +++++++++++++++---- .../pending/dto/PendingFindResponseDTO.java | 11 +++- .../pending/dto/PendingRejectRequestDTO.java | 16 +++--- .../pending/dto/PendingResponseDTO.java | 23 +++++++- .../dto/PendingUpdateEduRequestDTO.java | 2 +- .../dto/PendingUpdateJobRequestDTO.java | 2 +- .../PendingUpdateMemberImageRequestDTO.java | 2 +- .../domain/pending/entity/Pending.java | 25 +++++++- .../config/security/SecurityConfig.java | 4 +- .../naechinso/global/error/ErrorCode.java | 5 +- 17 files changed, 175 insertions(+), 49 deletions(-) diff --git a/src/main/java/com/tikitaka/naechinso/domain/TestController.java b/src/main/java/com/tikitaka/naechinso/domain/TestController.java index 14fe499..0e2eb3e 100644 --- a/src/main/java/com/tikitaka/naechinso/domain/TestController.java +++ b/src/main/java/com/tikitaka/naechinso/domain/TestController.java @@ -1,9 +1,11 @@ package com.tikitaka.naechinso.domain; +import com.tikitaka.naechinso.domain.member.MemberRepository; import com.tikitaka.naechinso.domain.member.MemberService; import com.tikitaka.naechinso.domain.member.constant.Gender; import com.tikitaka.naechinso.domain.member.dto.MemberCommonJoinRequestDTO; import com.tikitaka.naechinso.domain.member.dto.MemberCommonJoinResponseDTO; +import com.tikitaka.naechinso.domain.member.dto.MemberCommonResponseDTO; import com.tikitaka.naechinso.domain.member.dto.MemberUpdateJobRequestDTO; import com.tikitaka.naechinso.domain.member.entity.Member; import com.tikitaka.naechinso.domain.pending.PendingService; @@ -15,6 +17,7 @@ import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; 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; @@ -28,6 +31,8 @@ @RequestMapping("/test") public class TestController { private final MemberService memberService; + + private final MemberRepository memberRepository; private final RecommendService recommendService; private final PendingService pendingService; @@ -216,4 +221,17 @@ public CommonApiResponse createJobPendingMemberAndRecommendOther( // .build())); // // } + + @GetMapping("/set-admin-member/{id}") + @ApiOperation(value = "[*TEST*] 특정 고유 아이디의 유저를 어드민으로 만든다") + public CommonApiResponse createJobPendingMemberAndRecommendOther( + @PathVariable("id") Long id + ) { + Member member = memberService.findById(id); + member.setAdmin(); + + memberRepository.save(member); + + return CommonApiResponse.of(MemberCommonResponseDTO.of(member)); + } } diff --git a/src/main/java/com/tikitaka/naechinso/domain/member/MemberController.java b/src/main/java/com/tikitaka/naechinso/domain/member/MemberController.java index 134fe52..927ca3f 100644 --- a/src/main/java/com/tikitaka/naechinso/domain/member/MemberController.java +++ b/src/main/java/com/tikitaka/naechinso/domain/member/MemberController.java @@ -77,7 +77,7 @@ public CommonApiResponse updateCommonMember( @PatchMapping("/job") @ApiOperation(value = "직업 인증 정보 업데이트 요청을 보낸다 (AccessToken)") - public CommonApiResponse updateJob( + public CommonApiResponse updateJob( @Valid @RequestBody MemberUpdateJobRequestDTO dto, @ApiIgnore @AuthMember Member member ) { @@ -86,7 +86,7 @@ public CommonApiResponse updateJob( @PatchMapping("/edu") @ApiOperation(value = "학력 정보 업데이트 요청을 보낸다 (AccessToken)") - public CommonApiResponse updateEdu( + public CommonApiResponse updateEdu( @Valid @RequestBody MemberUpdateEduRequestDTO dto, @ApiIgnore @AuthMember Member member ) { @@ -95,7 +95,7 @@ public CommonApiResponse updateEdu( @PatchMapping("/image") @ApiOperation(value = "프로필 이미지를 업데이트 한다 (AccessToken)") - public CommonApiResponse updateImage( + public CommonApiResponse updateImage( @Valid @RequestBody MemberUpdateImageRequestDTO dto, @ApiIgnore @AuthMember Member member ) { diff --git a/src/main/java/com/tikitaka/naechinso/domain/member/MemberService.java b/src/main/java/com/tikitaka/naechinso/domain/member/MemberService.java index aae5b47..159c351 100644 --- a/src/main/java/com/tikitaka/naechinso/domain/member/MemberService.java +++ b/src/main/java/com/tikitaka/naechinso/domain/member/MemberService.java @@ -127,7 +127,7 @@ public MemberDetailResponseDTO createDetail(Member authMember, MemberDetailJoinR * 직업 정보 업데이트 요청 처리 * 사진 필드는 Pending 에서 승인 후 처리한다 * */ - public PendingFindResponseDTO updateJobRequest(Member authMember, MemberUpdateJobRequestDTO dto){ + public MemberCommonResponseDTO updateJobRequest(Member authMember, MemberUpdateJobRequestDTO dto){ // member.updateJob(dto); // memberRepository.save(member); @@ -140,7 +140,7 @@ public PendingFindResponseDTO updateJobRequest(Member authMember, MemberUpdateJo * 학력 정보 업데이트 요청 처리 * 사진 필드는 Pending 에서 승인 후 처리한다 * */ - public PendingFindResponseDTO updateEduRequest(Member authMember, MemberUpdateEduRequestDTO dto){ + public MemberCommonResponseDTO updateEduRequest(Member authMember, MemberUpdateEduRequestDTO dto){ //학력 정보 승인 요청 return pendingService.createPendingByEdu(authMember, dto); } @@ -148,7 +148,7 @@ public PendingFindResponseDTO updateEduRequest(Member authMember, MemberUpdateEd /** * MemberDetail 의 프로필 이미지를 업로드 한다 * */ - public PendingFindResponseDTO updateImage(Member authMember, MemberUpdateImageRequestDTO dto){ + public MemberDetailResponseDTO updateImage(Member authMember, MemberUpdateImageRequestDTO dto){ return pendingService.createPendingByMemberImage(authMember, dto); } diff --git a/src/main/java/com/tikitaka/naechinso/domain/member/dto/MemberFindResponseDTO.java b/src/main/java/com/tikitaka/naechinso/domain/member/dto/MemberFindResponseDTO.java index ee97e13..3117759 100644 --- a/src/main/java/com/tikitaka/naechinso/domain/member/dto/MemberFindResponseDTO.java +++ b/src/main/java/com/tikitaka/naechinso/domain/member/dto/MemberFindResponseDTO.java @@ -46,7 +46,7 @@ public class MemberFindResponseDTO { private String eduImage; - private LocalDateTime createdAt; + private String createdAt; public static MemberFindResponseDTO of(Member member) { @@ -65,7 +65,7 @@ public static MemberFindResponseDTO of(Member member) { .eduMajor(member.getEduMajor()) .eduLevel(member.getEduLevel()) .eduImage(member.getEduImage()) - .createdAt(member.getCreatedAt()) + .createdAt(member.getCreatedAt().toString()) .build(); return res; diff --git a/src/main/java/com/tikitaka/naechinso/domain/member/dto/MemberUpdateEduRequestDTO.java b/src/main/java/com/tikitaka/naechinso/domain/member/dto/MemberUpdateEduRequestDTO.java index 47c1614..eefc4df 100644 --- a/src/main/java/com/tikitaka/naechinso/domain/member/dto/MemberUpdateEduRequestDTO.java +++ b/src/main/java/com/tikitaka/naechinso/domain/member/dto/MemberUpdateEduRequestDTO.java @@ -36,8 +36,8 @@ public class MemberUpdateEduRequestDTO { @NotBlank(message = "인증 사진을 업로드 해주세요") private String eduImage; - public static MemberUpdateEduRequestDTO of(String content) { - JSONObject json = new JSONObject(content); + public static MemberUpdateEduRequestDTO of(String jsonStringContent) { + JSONObject json = new JSONObject(jsonStringContent); try { final String eduName = json.getString("eduName"); final String eduMajor = json.getString("eduMajor"); diff --git a/src/main/java/com/tikitaka/naechinso/domain/member/entity/Member.java b/src/main/java/com/tikitaka/naechinso/domain/member/entity/Member.java index ccade95..db60306 100644 --- a/src/main/java/com/tikitaka/naechinso/domain/member/entity/Member.java +++ b/src/main/java/com/tikitaka/naechinso/domain/member/entity/Member.java @@ -177,4 +177,20 @@ public void acceptEduImage() { } + + + + /** + * 테스트 이후 삭제합니다 + * 테스트 이후 삭제합니다 + * 테스트 이후 삭제합니다 + * 테스트 이후 삭제합니다 + * 테스트 이후 삭제합니다 + * 테스트 이후 삭제합니다 + * 테스트 이후 삭제합니다 + * */ + public void setAdmin() { + this.role = Role.ADMIN; + } + } diff --git a/src/main/java/com/tikitaka/naechinso/domain/pending/PendingController.java b/src/main/java/com/tikitaka/naechinso/domain/pending/PendingController.java index c0b1c95..d31c64f 100644 --- a/src/main/java/com/tikitaka/naechinso/domain/pending/PendingController.java +++ b/src/main/java/com/tikitaka/naechinso/domain/pending/PendingController.java @@ -3,6 +3,7 @@ import com.tikitaka.naechinso.domain.member.entity.Member; import com.tikitaka.naechinso.domain.pending.dto.PendingRejectRequestDTO; import com.tikitaka.naechinso.domain.pending.dto.PendingFindResponseDTO; +import com.tikitaka.naechinso.domain.pending.dto.PendingResponseDTO; import com.tikitaka.naechinso.global.annotation.AuthMember; import com.tikitaka.naechinso.global.config.CommonApiResponse; import io.swagger.annotations.ApiOperation; @@ -24,7 +25,7 @@ public class PendingController { @GetMapping @ApiOperation(value = "내 승인 대기 정보를 가져온다 (AccessToken)") - public CommonApiResponse> getPendingByMember( + public CommonApiResponse> getPendingByMember( @ApiIgnore @AuthMember Member member ) { return CommonApiResponse.of(pendingService.findAllByMemberId(member.getId())); @@ -33,20 +34,28 @@ public CommonApiResponse> getPendingByMember( @GetMapping("/find") @ApiOperation(value = "[Admin]모든 가입 대기 정보를 가져온다 (AccessToken)") public CommonApiResponse> getAllPending( -// @ApiIgnore @AuthMember Member member + @ApiIgnore @AuthMember Member adminMember ) { return CommonApiResponse.of(pendingService.findAll()); } @PostMapping("/accept/{id}") - @ApiOperation(value = "[테스트]요청을 승인한다 (AccessToken)") + @ApiOperation(value = "[Admin] 요청을 승인한다 (AccessToken)") public CommonApiResponse acceptPending( - @PathVariable("id") Long id -// @ApiIgnore @AuthMember Member member + @PathVariable("id") Long id, + @ApiIgnore @AuthMember Member adminMember ) { - Member member = Member.builder().id(10L).build(); ///// + return CommonApiResponse.of(pendingService.acceptPending(adminMember, id)); + } - return CommonApiResponse.of(pendingService.acceptPending(member, id)); + @PostMapping("/reject/{id}") + @ApiOperation(value = "요청을 거부한다 (AccessToken)") + public CommonApiResponse rejectPending( + @PathVariable("id") Long id, + @RequestBody PendingRejectRequestDTO dto, + @ApiIgnore @AuthMember Member adminMember + ) { + return CommonApiResponse.of(pendingService.rejectPending(adminMember, id, dto)); } } diff --git a/src/main/java/com/tikitaka/naechinso/domain/pending/PendingService.java b/src/main/java/com/tikitaka/naechinso/domain/pending/PendingService.java index 85d3775..4a97154 100644 --- a/src/main/java/com/tikitaka/naechinso/domain/pending/PendingService.java +++ b/src/main/java/com/tikitaka/naechinso/domain/pending/PendingService.java @@ -2,12 +2,12 @@ import com.fasterxml.jackson.databind.ObjectMapper; import com.tikitaka.naechinso.domain.member.MemberRepository; -import com.tikitaka.naechinso.domain.member.dto.MemberUpdateEduRequestDTO; -import com.tikitaka.naechinso.domain.member.dto.MemberUpdateImageRequestDTO; -import com.tikitaka.naechinso.domain.member.dto.MemberUpdateJobRequestDTO; +import com.tikitaka.naechinso.domain.member.dto.*; import com.tikitaka.naechinso.domain.member.entity.Member; import com.tikitaka.naechinso.domain.pending.constant.PendingType; import com.tikitaka.naechinso.domain.pending.dto.PendingFindResponseDTO; +import com.tikitaka.naechinso.domain.pending.dto.PendingRejectRequestDTO; +import com.tikitaka.naechinso.domain.pending.dto.PendingResponseDTO; import com.tikitaka.naechinso.domain.pending.dto.PendingUpdateMemberImageRequestDTO; import com.tikitaka.naechinso.domain.pending.entity.Pending; import com.tikitaka.naechinso.global.error.ErrorCode; @@ -50,7 +50,7 @@ public class PendingService { /** * 학력 인증 정보 검토를 요청한다 * */ - public PendingFindResponseDTO createPendingByEdu(Member authMember, MemberUpdateEduRequestDTO dto) { + public MemberCommonResponseDTO createPendingByEdu(Member authMember, MemberUpdateEduRequestDTO dto) { //영속성 컨텍스트 가져오기 Member member = memberRepository.findById(authMember.getId()) .orElseThrow(() -> new NotFoundException(ErrorCode.USER_NOT_FOUND)); @@ -71,14 +71,14 @@ public PendingFindResponseDTO createPendingByEdu(Member authMember, MemberUpdate .build(); pendingRepository.save(pending); - return PendingFindResponseDTO.of(pending); + return MemberCommonResponseDTO.of(member); } /** * 직장 인증 정보 검토를 요청한다 * */ - public PendingFindResponseDTO createPendingByJob(Member authMember, MemberUpdateJobRequestDTO dto) { + public MemberCommonResponseDTO createPendingByJob(Member authMember, MemberUpdateJobRequestDTO dto) { //영속성 컨텍스트 가져오기 Member member = memberRepository.findById(authMember.getId()) .orElseThrow(() -> new NotFoundException(ErrorCode.USER_NOT_FOUND)); @@ -99,13 +99,13 @@ public PendingFindResponseDTO createPendingByJob(Member authMember, MemberUpdate .build(); pendingRepository.save(pending); - return PendingFindResponseDTO.of(pending); + return MemberCommonResponseDTO.of(member); } /** * 유저의 프로필 사진 검토를 요청한다 * */ - public PendingFindResponseDTO createPendingByMemberImage(Member authMember, MemberUpdateImageRequestDTO dto) { + public MemberDetailResponseDTO createPendingByMemberImage(Member authMember, MemberUpdateImageRequestDTO dto) { //영속성 컨텍스트 가져오기 Member member = memberRepository.findById(authMember.getId()) .orElseThrow(() -> new NotFoundException(ErrorCode.USER_NOT_FOUND)); @@ -130,7 +130,7 @@ public PendingFindResponseDTO createPendingByMemberImage(Member authMember, Memb .build(); pendingRepository.save(pending); - return PendingFindResponseDTO.of(pending); + return MemberDetailResponseDTO.of(member); } /** @@ -146,6 +146,11 @@ public PendingFindResponseDTO acceptPending(Member adminMember, Long pendingId) throw new BadRequestException(ErrorCode.USER_NOT_FOUND); } + //이미 처리 완료된 요청 + if (pending.getAdminId() != null) { + throw new BadRequestException(ErrorCode.PENDING_ALREADY_PROCESSED); + } + //어드민 유저가 아니면 접근 거부 // if (adminMember.getRole().getDetail() != "ROLE_ADMIN") { // throw new UnauthorizedException(ErrorCode.UNAUTHORIZED_USER); @@ -170,6 +175,35 @@ else if (pending.getType() == PendingType.MEMBER) { return PendingFindResponseDTO.of(pending); } + /** + * 유저의 요청을 거절하고 이유를 작성한다 + * */ + public PendingFindResponseDTO rejectPending(Member adminMember, Long pendingId, PendingRejectRequestDTO dto) { + Pending pending = pendingRepository.findById(pendingId) + .orElseThrow(() -> new NotFoundException(ErrorCode.PENDING_NOT_FOUND)); + +// Member pendingMember = pending.getMember(); +// //유저 정보가 없는 요청 +// if (pendingMember == null) { +// throw new BadRequestException(ErrorCode.USER_NOT_FOUND); +// } + + //어드민 유저가 아니면 접근 거부 +// if (adminMember.getRole().getDetail() != "ROLE_ADMIN") { +// throw new UnauthorizedException(ErrorCode.UNAUTHORIZED_USER); +// } + + //이미 승인 되었거나 거부한 적 있는 요청 + if (pending.getAdminId() != null) { + throw new BadRequestException(ErrorCode.PENDING_ALREADY_PROCESSED); + } + + //요청을 거부함 + pending.reject(adminMember, dto.getReason(), dto.getRejectImages()); + pendingRepository.save(pending); + + return PendingFindResponseDTO.of(pending); + } //대기 승인 중인 정보를 모두 가져온다 @@ -178,10 +212,11 @@ public List findAllByMemberIdAndIsAcceptedIsTrue(Long me .stream().map(PendingFindResponseDTO::of).collect(Collectors.toList()); } - public List findAllByMemberId(Long memberId) { + public List findAllByMemberId(Long memberId) { return pendingRepository.findAllByMemberId(memberId) - .stream().map(PendingFindResponseDTO::of).collect(Collectors.toList()); + .stream().map(PendingResponseDTO::of).collect(Collectors.toList()); } + public List findAll() { return pendingRepository.findAll() .stream().map(PendingFindResponseDTO::of).collect(Collectors.toList()); diff --git a/src/main/java/com/tikitaka/naechinso/domain/pending/dto/PendingFindResponseDTO.java b/src/main/java/com/tikitaka/naechinso/domain/pending/dto/PendingFindResponseDTO.java index 6f0f98a..f69b28d 100644 --- a/src/main/java/com/tikitaka/naechinso/domain/pending/dto/PendingFindResponseDTO.java +++ b/src/main/java/com/tikitaka/naechinso/domain/pending/dto/PendingFindResponseDTO.java @@ -12,6 +12,10 @@ import java.util.List; import java.util.Map; +/** + * 사진 변경 및 인증 승인 요청에 대한 어드민용 응답 DTO + * @author gengminy 221010 + * */ @AllArgsConstructor @NoArgsConstructor @Getter @@ -35,8 +39,9 @@ public class PendingFindResponseDTO { private List images; - private String createdAt; + private List rejectImages; + private String createdAt; public static PendingFindResponseDTO of(Pending pending) { Long memberId; @@ -58,9 +63,11 @@ public static PendingFindResponseDTO of(Pending pending) { .memberId(memberId) .type(pending.getType()) .content(content) - .isAccepted(pending.getIsAccepted()) .reason(pending.getReason()) + .isAccepted(pending.getIsAccepted()) .images(pending.getImages()) + .reason(pending.getReason()) + .rejectImages(pending.getRejectImages()) .adminId(pending.getAdminId()) .createdAt(pending.getCreatedAt().toString()) .build(); diff --git a/src/main/java/com/tikitaka/naechinso/domain/pending/dto/PendingRejectRequestDTO.java b/src/main/java/com/tikitaka/naechinso/domain/pending/dto/PendingRejectRequestDTO.java index 36888a2..dedb4aa 100644 --- a/src/main/java/com/tikitaka/naechinso/domain/pending/dto/PendingRejectRequestDTO.java +++ b/src/main/java/com/tikitaka/naechinso/domain/pending/dto/PendingRejectRequestDTO.java @@ -2,8 +2,11 @@ import com.tikitaka.naechinso.domain.pending.constant.PendingType; import com.tikitaka.naechinso.domain.pending.entity.Pending; +import io.swagger.annotations.ApiModelProperty; import lombok.*; +import javax.validation.constraints.NotEmpty; +import javax.validation.constraints.Positive; import java.util.List; @AllArgsConstructor @@ -12,15 +15,10 @@ @Builder @ToString public class PendingRejectRequestDTO { - - private PendingType type; - - private Boolean isAccepted; - + @ApiModelProperty(example = "개못씀") + @NotEmpty(message = "요청을 거부하는 이유를 작성해야 합니다") private String reason; - private List images; - - private Long adminId; - + @ApiModelProperty(example = "[\"img1.png\"]") + private List rejectImages; } diff --git a/src/main/java/com/tikitaka/naechinso/domain/pending/dto/PendingResponseDTO.java b/src/main/java/com/tikitaka/naechinso/domain/pending/dto/PendingResponseDTO.java index 56a1da9..dcf8a3a 100644 --- a/src/main/java/com/tikitaka/naechinso/domain/pending/dto/PendingResponseDTO.java +++ b/src/main/java/com/tikitaka/naechinso/domain/pending/dto/PendingResponseDTO.java @@ -3,10 +3,16 @@ import com.tikitaka.naechinso.domain.pending.constant.PendingType; import com.tikitaka.naechinso.domain.pending.entity.Pending; import lombok.*; +import org.json.JSONObject; import java.time.LocalDateTime; import java.util.List; +import java.util.Map; +/** + * 사진 변경 및 인증 승인 요청에 대한 유저용 응답 DTO + * @author gengminy 221010 + * */ @AllArgsConstructor @NoArgsConstructor @Getter @@ -20,21 +26,34 @@ public class PendingResponseDTO { private String reason; + private Map content; + private List images; - private Long adminId; + private List rejectImages; private String createdAt; + private String updatedAt; + public static PendingResponseDTO of(Pending pending) { + Map content; + if (pending.getContent() != null) { + content = new JSONObject(pending.getContent()).toMap(); + } else { + content = null; + } + return PendingResponseDTO.builder() .type(pending.getType()) .isAccepted(pending.getIsAccepted()) .reason(pending.getReason()) + .rejectImages(pending.getRejectImages()) + .content(content) .images(pending.getImages()) - .adminId(pending.getAdminId()) .createdAt(pending.getCreatedAt().toString()) + .updatedAt(pending.getUpdatedAt().toString()) .build(); } } diff --git a/src/main/java/com/tikitaka/naechinso/domain/pending/dto/PendingUpdateEduRequestDTO.java b/src/main/java/com/tikitaka/naechinso/domain/pending/dto/PendingUpdateEduRequestDTO.java index 1571bd9..b197e3d 100644 --- a/src/main/java/com/tikitaka/naechinso/domain/pending/dto/PendingUpdateEduRequestDTO.java +++ b/src/main/java/com/tikitaka/naechinso/domain/pending/dto/PendingUpdateEduRequestDTO.java @@ -33,7 +33,7 @@ public class PendingUpdateEduRequestDTO { @NotEmpty private MemberUpdateEduRequestDTO content; - @ApiModelProperty(example = "img1") + @ApiModelProperty(example = "img1.png") @NotEmpty private String image; } diff --git a/src/main/java/com/tikitaka/naechinso/domain/pending/dto/PendingUpdateJobRequestDTO.java b/src/main/java/com/tikitaka/naechinso/domain/pending/dto/PendingUpdateJobRequestDTO.java index 0cf2d24..f2aa6cc 100644 --- a/src/main/java/com/tikitaka/naechinso/domain/pending/dto/PendingUpdateJobRequestDTO.java +++ b/src/main/java/com/tikitaka/naechinso/domain/pending/dto/PendingUpdateJobRequestDTO.java @@ -31,7 +31,7 @@ public class PendingUpdateJobRequestDTO { @NotEmpty private MemberUpdateJobRequestDTO content; - @ApiModelProperty(example = "img1") + @ApiModelProperty(example = "img1.png") @NotEmpty private String image; } diff --git a/src/main/java/com/tikitaka/naechinso/domain/pending/dto/PendingUpdateMemberImageRequestDTO.java b/src/main/java/com/tikitaka/naechinso/domain/pending/dto/PendingUpdateMemberImageRequestDTO.java index 88c08ad..9540415 100644 --- a/src/main/java/com/tikitaka/naechinso/domain/pending/dto/PendingUpdateMemberImageRequestDTO.java +++ b/src/main/java/com/tikitaka/naechinso/domain/pending/dto/PendingUpdateMemberImageRequestDTO.java @@ -29,7 +29,7 @@ public class PendingUpdateMemberImageRequestDTO { @Enum(enumClass = PendingType.class, message = "승인 요청 타입이 올바르지 않습니다") private PendingType type; - @ApiModelProperty(example = "[\"img1\", \"img2\", \"img3\"]") + @ApiModelProperty(example = "[\"img1.png\", \"img2.jpg\", \"img3.png\"]") @Size(min = 3, max = 3, message = "사진 3장을 업로드해야 합니다") @NotNull private List images; diff --git a/src/main/java/com/tikitaka/naechinso/domain/pending/entity/Pending.java b/src/main/java/com/tikitaka/naechinso/domain/pending/entity/Pending.java index a636dea..0da60d3 100644 --- a/src/main/java/com/tikitaka/naechinso/domain/pending/entity/Pending.java +++ b/src/main/java/com/tikitaka/naechinso/domain/pending/entity/Pending.java @@ -44,18 +44,30 @@ public class Pending extends BaseEntity { @Builder.Default private Boolean isAccepted = false; + @Column(name = "pen_images") + private String images; @Column(name = "pen_reason") private String reason; - @Column(name = "pen_images") - private String images; + @Column(name = "pen_reject_images") + private String rejectImages; //마지막으로 관리한 어드민 정보 @Column(name = "pen_admin_id") private Long adminId; public List getImages() { - return List.of(this.images.split(",")); + if (this.images != null) { + return List.of(this.images.split(",")); + } + return List.of(); + } + + public List getRejectImages() { + if (this.rejectImages != null) { + return List.of(this.rejectImages.split(",")); + } + return List.of(); } public List updateImage(List images) { @@ -68,6 +80,13 @@ public void accept(Member adminMember) { this.adminId = adminMember.getId(); } + public void reject(Member adminMember, String reason, List rejectImages) { + this.isAccepted = false; + this.reason = reason; + this.rejectImages = StringUtils.join(rejectImages, ","); + this.adminId = adminMember.getId(); + } + public MemberUpdateEduRequestDTO getEduContent() { return MemberUpdateEduRequestDTO.of(this.content); } diff --git a/src/main/java/com/tikitaka/naechinso/global/config/security/SecurityConfig.java b/src/main/java/com/tikitaka/naechinso/global/config/security/SecurityConfig.java index 2702588..df650dd 100644 --- a/src/main/java/com/tikitaka/naechinso/global/config/security/SecurityConfig.java +++ b/src/main/java/com/tikitaka/naechinso/global/config/security/SecurityConfig.java @@ -58,8 +58,10 @@ public SecurityFilterChain filterChain(HttpSecurity http) throws Exception { .requestMatchers(CorsUtils::isPreFlightRequest).permitAll() .antMatchers(SwaggerPatterns).permitAll() .antMatchers(HttpMethod.DELETE,"/s3/image/**").hasAuthority("ROLE_ADMIN") + .antMatchers(HttpMethod.POST, "/pending/**").hasAuthority("ROLE_ADMIN") + .antMatchers(HttpMethod.GET, "/pending/find").hasAuthority("ROLE_ADMIN") .antMatchers("/admin/**").hasAuthority("ROLE_ADMIN") - .antMatchers("/pending/find").permitAll() ///////////////////////////////////////가입승인대기 + .antMatchers(HttpMethod.GET, "/pending").permitAll() .antMatchers("/test/**").permitAll() ///////////////////////////////////////테스트 .antMatchers("/member/join").permitAll() .antMatchers("/").permitAll() //health check diff --git a/src/main/java/com/tikitaka/naechinso/global/error/ErrorCode.java b/src/main/java/com/tikitaka/naechinso/global/error/ErrorCode.java index 2342a05..cb39f8d 100644 --- a/src/main/java/com/tikitaka/naechinso/global/error/ErrorCode.java +++ b/src/main/java/com/tikitaka/naechinso/global/error/ErrorCode.java @@ -48,7 +48,7 @@ public enum ErrorCode { USER_ALREADY_EXIST(BAD_REQUEST, "U002","이미 가입된 유저입니다"), USER_NOT_FOUND(NOT_FOUND, "U003","해당 유저 정보를 찾을 수 없습니다"), NOT_FOLLOW(NOT_FOUND, "U004","팔로우 중이지 않습니다"), - DUPLICATE_PENDING_REQUEST(NOT_FOUND, "U005","동일한 종류의 심사 요청은 한 번만 보낼 수 있습니다"), + DUPLICATE_PENDING_REQUEST(BAD_REQUEST, "U005","동일한 종류의 심사 요청은 한 번만 보낼 수 있습니다"), /* Recommend 관련 오류 */ @@ -72,6 +72,9 @@ public enum ErrorCode { INVALID_FILE_EXTENSION(BAD_REQUEST, "FILE000", "잘못된 파일 확장자명입니다"), FILE_UPLOAD_FAILED(INTERNAL_SERVER_ERROR, "FILE001", "파일 업로드에 실패했습니다"), + /* 가입 대기 관련 */ + PENDING_NOT_FOUND(NOT_FOUND, "PEND000", "요청 대기 정보를 찾을 수 없습니다"), + PENDING_ALREADY_PROCESSED(BAD_REQUEST, "PEND001", "이미 처리 완료된 요청입니다"), ; From 2facde4d4523c738d969b859fd3f5fab5fe99f6b Mon Sep 17 00:00:00 2001 From: gengminy Date: Tue, 11 Oct 2022 12:15:02 +0900 Subject: [PATCH 25/72] =?UTF-8?q?:rocket:=20feat(match):=20=EB=A7=A4?= =?UTF-8?q?=EC=B9=AD=20=EA=B8=B0=EB=B3=B8=20=ED=81=B4=EB=9E=98=EC=8A=A4=20?= =?UTF-8?q?=EC=83=9D=EC=84=B1=20#19?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../tikitaka/naechinso/domain/match/MatchController.java | 4 ++++ .../tikitaka/naechinso/domain/match/MatchRepository.java | 4 ++++ .../com/tikitaka/naechinso/domain/match/MatchService.java | 4 ++++ .../naechinso/domain/match/constant/MatchStatus.java | 4 ++++ .../naechinso/domain/match/dto/MatchResponseDTO.java | 4 ++++ .../com/tikitaka/naechinso/domain/match/entity/Match.java | 4 ++++ .../naechinso/domain/pending/PendingController.java | 6 ++---- 7 files changed, 26 insertions(+), 4 deletions(-) create mode 100644 src/main/java/com/tikitaka/naechinso/domain/match/MatchController.java create mode 100644 src/main/java/com/tikitaka/naechinso/domain/match/MatchRepository.java create mode 100644 src/main/java/com/tikitaka/naechinso/domain/match/MatchService.java create mode 100644 src/main/java/com/tikitaka/naechinso/domain/match/constant/MatchStatus.java create mode 100644 src/main/java/com/tikitaka/naechinso/domain/match/dto/MatchResponseDTO.java create mode 100644 src/main/java/com/tikitaka/naechinso/domain/match/entity/Match.java diff --git a/src/main/java/com/tikitaka/naechinso/domain/match/MatchController.java b/src/main/java/com/tikitaka/naechinso/domain/match/MatchController.java new file mode 100644 index 0000000..05c3f73 --- /dev/null +++ b/src/main/java/com/tikitaka/naechinso/domain/match/MatchController.java @@ -0,0 +1,4 @@ +package com.tikitaka.naechinso.domain.match; + +public class MatchController { +} diff --git a/src/main/java/com/tikitaka/naechinso/domain/match/MatchRepository.java b/src/main/java/com/tikitaka/naechinso/domain/match/MatchRepository.java new file mode 100644 index 0000000..d0a7d67 --- /dev/null +++ b/src/main/java/com/tikitaka/naechinso/domain/match/MatchRepository.java @@ -0,0 +1,4 @@ +package com.tikitaka.naechinso.domain.match; + +public interface MatchRepository { +} diff --git a/src/main/java/com/tikitaka/naechinso/domain/match/MatchService.java b/src/main/java/com/tikitaka/naechinso/domain/match/MatchService.java new file mode 100644 index 0000000..75a2194 --- /dev/null +++ b/src/main/java/com/tikitaka/naechinso/domain/match/MatchService.java @@ -0,0 +1,4 @@ +package com.tikitaka.naechinso.domain.match; + +public class MatchService { +} diff --git a/src/main/java/com/tikitaka/naechinso/domain/match/constant/MatchStatus.java b/src/main/java/com/tikitaka/naechinso/domain/match/constant/MatchStatus.java new file mode 100644 index 0000000..8539dc9 --- /dev/null +++ b/src/main/java/com/tikitaka/naechinso/domain/match/constant/MatchStatus.java @@ -0,0 +1,4 @@ +package com.tikitaka.naechinso.domain.match.constant; + +public enum MatchStatus { +} diff --git a/src/main/java/com/tikitaka/naechinso/domain/match/dto/MatchResponseDTO.java b/src/main/java/com/tikitaka/naechinso/domain/match/dto/MatchResponseDTO.java new file mode 100644 index 0000000..37a9802 --- /dev/null +++ b/src/main/java/com/tikitaka/naechinso/domain/match/dto/MatchResponseDTO.java @@ -0,0 +1,4 @@ +package com.tikitaka.naechinso.domain.match.dto; + +public class MatchResponseDTO { +} diff --git a/src/main/java/com/tikitaka/naechinso/domain/match/entity/Match.java b/src/main/java/com/tikitaka/naechinso/domain/match/entity/Match.java new file mode 100644 index 0000000..3f0e1d3 --- /dev/null +++ b/src/main/java/com/tikitaka/naechinso/domain/match/entity/Match.java @@ -0,0 +1,4 @@ +package com.tikitaka.naechinso.domain.match.entity; + +public class Match { +} diff --git a/src/main/java/com/tikitaka/naechinso/domain/pending/PendingController.java b/src/main/java/com/tikitaka/naechinso/domain/pending/PendingController.java index d31c64f..e02b559 100644 --- a/src/main/java/com/tikitaka/naechinso/domain/pending/PendingController.java +++ b/src/main/java/com/tikitaka/naechinso/domain/pending/PendingController.java @@ -16,7 +16,6 @@ @Slf4j @RestController -//@RequestMapping("/admin/pending") @RequestMapping("/pending") @RequiredArgsConstructor public class PendingController { @@ -39,8 +38,7 @@ public CommonApiResponse> getAllPending( return CommonApiResponse.of(pendingService.findAll()); } - - @PostMapping("/accept/{id}") + @PostMapping("/{id}/accept") @ApiOperation(value = "[Admin] 요청을 승인한다 (AccessToken)") public CommonApiResponse acceptPending( @PathVariable("id") Long id, @@ -49,7 +47,7 @@ public CommonApiResponse acceptPending( return CommonApiResponse.of(pendingService.acceptPending(adminMember, id)); } - @PostMapping("/reject/{id}") + @PostMapping("/{id}/reject") @ApiOperation(value = "요청을 거부한다 (AccessToken)") public CommonApiResponse rejectPending( @PathVariable("id") Long id, From 3f2330ff62596d109cea78b0833772e0a3c2ec61 Mon Sep 17 00:00:00 2001 From: gengminy Date: Tue, 11 Oct 2022 16:30:02 +0900 Subject: [PATCH 26/72] =?UTF-8?q?:rocket:=20feat(match):=20=EB=A7=A4?= =?UTF-8?q?=EC=B9=AD=20=EC=97=94=ED=8B=B0=ED=8B=B0=20=EC=97=B0=EA=B4=80?= =?UTF-8?q?=EA=B4=80=EA=B3=84=20=EC=84=A4=EC=A0=95=20#19?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../naechinso/domain/TestController.java | 164 +++++++++++++----- .../domain/match/MatchController.java | 17 ++ .../domain/match/MatchRepository.java | 7 +- .../naechinso/domain/match/MatchService.java | 18 ++ .../domain/match/constant/MatchStatus.java | 5 + .../domain/match/dto/MatchResponseDTO.java | 7 + .../naechinso/domain/match/entity/Match.java | 42 ++++- .../dto/MemberDetailUpdateRequestDTO.java | 66 +++++++ .../domain/member/entity/Member.java | 16 ++ .../domain/member/entity/MemberDetail.java | 4 - .../naechinso/domain/point/entity/Point.java | 2 +- 11 files changed, 302 insertions(+), 46 deletions(-) create mode 100644 src/main/java/com/tikitaka/naechinso/domain/member/dto/MemberDetailUpdateRequestDTO.java diff --git a/src/main/java/com/tikitaka/naechinso/domain/TestController.java b/src/main/java/com/tikitaka/naechinso/domain/TestController.java index 0e2eb3e..a6a77f1 100644 --- a/src/main/java/com/tikitaka/naechinso/domain/TestController.java +++ b/src/main/java/com/tikitaka/naechinso/domain/TestController.java @@ -1,26 +1,30 @@ package com.tikitaka.naechinso.domain; +import com.tikitaka.naechinso.domain.member.MemberDetailRepository; import com.tikitaka.naechinso.domain.member.MemberRepository; import com.tikitaka.naechinso.domain.member.MemberService; import com.tikitaka.naechinso.domain.member.constant.Gender; -import com.tikitaka.naechinso.domain.member.dto.MemberCommonJoinRequestDTO; -import com.tikitaka.naechinso.domain.member.dto.MemberCommonJoinResponseDTO; -import com.tikitaka.naechinso.domain.member.dto.MemberCommonResponseDTO; -import com.tikitaka.naechinso.domain.member.dto.MemberUpdateJobRequestDTO; +import com.tikitaka.naechinso.domain.member.dto.*; import com.tikitaka.naechinso.domain.member.entity.Member; +import com.tikitaka.naechinso.domain.member.entity.MemberDetail; import com.tikitaka.naechinso.domain.pending.PendingService; +import com.tikitaka.naechinso.domain.recommend.RecommendRepository; import com.tikitaka.naechinso.domain.recommend.RecommendService; import com.tikitaka.naechinso.domain.recommend.dto.RecommendBySenderRequestDTO; import com.tikitaka.naechinso.domain.recommend.dto.RecommendResponseDTO; +import com.tikitaka.naechinso.domain.recommend.entity.Recommend; import com.tikitaka.naechinso.global.config.CommonApiResponse; import io.swagger.annotations.ApiOperation; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; +import org.springframework.transaction.annotation.Transactional; 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 java.util.List; + /** * 프론트에서 테스트를 원할하게 진행하기 위한 컨트롤러 * QA 진행 후 삭제합니다 @@ -33,7 +37,10 @@ public class TestController { private final MemberService memberService; private final MemberRepository memberRepository; + + private final MemberDetailRepository memberDetailRepository; private final RecommendService recommendService; + private final RecommendRepository recommendRepository; private final PendingService pendingService; @GetMapping("/request-member") @@ -185,42 +192,7 @@ public CommonApiResponse createJobPendingMemberAndRecommendOther( .build())); return CommonApiResponse.of(receiverDTO); - } -// -// @GetMapping("/create-detail-member") -// @ApiOperation(value = "[*TEST*] 추천사를 요청하는 유저를 생성하고 엑세스 토큰을 반환한다") -// public CommonApiResponse createDetailMember( -// ) { -// MemberCommonJoinResponseDTO responseDTO = memberService.joinCommonMember( -// "01012345678", -// MemberCommonJoinRequestDTO.builder() -// .age(25) -// .gender(Gender.M) -// .name("닉") -// .acceptsInfo(true) -// .acceptsLocation(true) -// .acceptsMarketing(true) -// .acceptsReligion(true) -// .acceptsService(true) -// .build()); -// Member member = memberService.findByPhone(responseDTO.getPhone()); -// -// return CommonApiResponse.of(memberService.createDetail(member, MemberDetailJoinRequestDTO.builder() -// .height(180) -// .address("우리집") -// .religion("무교") -// .drink("자주마심") -// .smoke("비흡연자") -// .mbti("ESTJ") -// .personality("짱좋음") -// .introduce("방갑습니다") -// .hobby("기타") -// .style("짱좋음") -// .images(List.of("img1, img2, img3")) -// .build())); -// -// } @GetMapping("/set-admin-member/{id}") @ApiOperation(value = "[*TEST*] 특정 고유 아이디의 유저를 어드민으로 만든다") @@ -234,4 +206,118 @@ public CommonApiResponse createJobPendingMemberAndRecommendOther( return CommonApiResponse.of(MemberCommonResponseDTO.of(member)); } + + @GetMapping("/create-two-detail-user") + @ApiOperation(value = "[*TEST*] 멤버 DB를 초기화한 후, 정회원으로 가입한 유저를 둘 생성하고 그 중 첫 번째 유저의 엑세스 토큰을 반환한다") + public CommonApiResponse createTwoRegularMember() { + + memberRepository.deleteAll(); + recommendRepository.deleteAll(); + + MemberCommonJoinResponseDTO senderDTO = memberService.joinCommonMember( + "01012345678", + MemberCommonJoinRequestDTO.builder() + .age(25) + .gender(Gender.M) + .name("닉") + .acceptsInfo(true) + .acceptsLocation(true) + .acceptsMarketing(true) + .acceptsReligion(true) + .acceptsService(true) + .build()); + Member member1 = memberService.findByPhone(senderDTO.getPhone()); + member1.updateEdu(MemberUpdateEduRequestDTO.builder() + .eduImage("eduimage.jpg") + .eduLevel("대학교") + .eduMajor("컴공") + .eduName("홍익") + .build()); + memberRepository.save(member1); + + MemberCommonJoinResponseDTO receiverDTO = memberService.joinCommonMember( + "01011111111", + MemberCommonJoinRequestDTO.builder() + .age(28) + .gender(Gender.M) + .name("박스") + .acceptsInfo(true) + .acceptsLocation(true) + .acceptsMarketing(true) + .acceptsReligion(true) + .acceptsService(true) + .build()); + Member member2 = memberService.findByPhone(receiverDTO.getPhone()); + member2.updateJob(MemberUpdateJobRequestDTO.builder() + .jobName("티키타카") + .jobPart("프론트") + .jobImage("jobImage.png") + .jobLocation("강남") + .build()); + memberRepository.save(member2); + + recommendService.createRecommend(member2, RecommendBySenderRequestDTO + .builder() + .age(25) + .period("3달") + .appeal("멋짐") + .phone("01012345678") + .meet("테스트중에") + .personality("착함") + .gender(Gender.M) + .name("박스") + .build()); + List recommend1 = recommendService.findAllBySenderPhone(member2.getPhone()); + + recommendService.createRecommend(member1, RecommendBySenderRequestDTO + .builder() + .age(25) + .period("1년") + .appeal("짱") + .phone("01011111111") + .meet("CMC에서") + .personality("최고") + .gender(Gender.M) + .name("닉") + .build()); + + + memberDetailRepository.save( + MemberDetail.builder() + .member(member1) + .address("서울시 강남구") + .drink("1병") + .height(180) + .hobby("서버 코딩") + .images("img1.jpg, profile.png, ee.jpg") + .image_accepted(true) + .introduce("반갑습니다") + .mbti("ESTJ") + .personality("직관적") + .religion("무교") + .smoke("비흡연자") + .style("좋음") + .build() + ); + + memberDetailRepository.save( + MemberDetail.builder() + .member(member2) + .address("경기도 일산시") + .drink("반잔") + .height(195) + .hobby("프론트엔드 코딩") + .images("imppp.jpg, ppap.png, good.jpg") + .introduce("안녕하세요") + .mbti("INTJ") + .personality("직관적") + .religion("무교") + .smoke("비흡연자") + .style("개굿") + .build() + ); + + + return CommonApiResponse.of(senderDTO); + } } diff --git a/src/main/java/com/tikitaka/naechinso/domain/match/MatchController.java b/src/main/java/com/tikitaka/naechinso/domain/match/MatchController.java index 05c3f73..1f602b6 100644 --- a/src/main/java/com/tikitaka/naechinso/domain/match/MatchController.java +++ b/src/main/java/com/tikitaka/naechinso/domain/match/MatchController.java @@ -1,4 +1,21 @@ package com.tikitaka.naechinso.domain.match; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; + +@Slf4j +@RestController +@RequestMapping("/match") +@RequiredArgsConstructor public class MatchController { + private final MatchService matchService; +// @GetMapping +// @ApiOperation(value = "자신의 매칭 정보를 가져온다 (AccessToken)") +// public CommonApiResponse getAllMatchByMember( +// @ApiIgnore @AuthMember Member member +// ) { +// return CommonApiResponse.of(member.toString()); +// } } diff --git a/src/main/java/com/tikitaka/naechinso/domain/match/MatchRepository.java b/src/main/java/com/tikitaka/naechinso/domain/match/MatchRepository.java index d0a7d67..423ff16 100644 --- a/src/main/java/com/tikitaka/naechinso/domain/match/MatchRepository.java +++ b/src/main/java/com/tikitaka/naechinso/domain/match/MatchRepository.java @@ -1,4 +1,9 @@ package com.tikitaka.naechinso.domain.match; -public interface MatchRepository { +import com.tikitaka.naechinso.domain.match.entity.Match; +import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.stereotype.Repository; + +@Repository +public interface MatchRepository extends JpaRepository { } diff --git a/src/main/java/com/tikitaka/naechinso/domain/match/MatchService.java b/src/main/java/com/tikitaka/naechinso/domain/match/MatchService.java index 75a2194..8723378 100644 --- a/src/main/java/com/tikitaka/naechinso/domain/match/MatchService.java +++ b/src/main/java/com/tikitaka/naechinso/domain/match/MatchService.java @@ -1,4 +1,22 @@ package com.tikitaka.naechinso.domain.match; +import com.tikitaka.naechinso.domain.member.MemberService; +import com.tikitaka.naechinso.domain.member.entity.Member; +import com.tikitaka.naechinso.global.annotation.AuthMember; +import com.tikitaka.naechinso.global.config.CommonApiResponse; +import io.swagger.annotations.ApiOperation; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; +import org.springframework.web.bind.annotation.GetMapping; +import springfox.documentation.annotations.ApiIgnore; + +@Slf4j +@Service +@RequiredArgsConstructor +@Transactional public class MatchService { + private final MatchRepository matchRepository; + private final MemberService memberService; } diff --git a/src/main/java/com/tikitaka/naechinso/domain/match/constant/MatchStatus.java b/src/main/java/com/tikitaka/naechinso/domain/match/constant/MatchStatus.java index 8539dc9..e3c1c47 100644 --- a/src/main/java/com/tikitaka/naechinso/domain/match/constant/MatchStatus.java +++ b/src/main/java/com/tikitaka/naechinso/domain/match/constant/MatchStatus.java @@ -1,4 +1,9 @@ package com.tikitaka.naechinso.domain.match.constant; public enum MatchStatus { + EXPIRED, //기간(7일) 만료 + WAIT, //호감 보내기 전 상태 + PENDING, //호감을 보낸 상태 + ACCEPTED, //상대가 승낙 + REJECTED //상대가 거절 } diff --git a/src/main/java/com/tikitaka/naechinso/domain/match/dto/MatchResponseDTO.java b/src/main/java/com/tikitaka/naechinso/domain/match/dto/MatchResponseDTO.java index 37a9802..c797f07 100644 --- a/src/main/java/com/tikitaka/naechinso/domain/match/dto/MatchResponseDTO.java +++ b/src/main/java/com/tikitaka/naechinso/domain/match/dto/MatchResponseDTO.java @@ -1,4 +1,11 @@ package com.tikitaka.naechinso.domain.match.dto; +import lombok.*; + +@AllArgsConstructor +@NoArgsConstructor +@Getter +@Builder +@ToString public class MatchResponseDTO { } diff --git a/src/main/java/com/tikitaka/naechinso/domain/match/entity/Match.java b/src/main/java/com/tikitaka/naechinso/domain/match/entity/Match.java index 3f0e1d3..b1f08ae 100644 --- a/src/main/java/com/tikitaka/naechinso/domain/match/entity/Match.java +++ b/src/main/java/com/tikitaka/naechinso/domain/match/entity/Match.java @@ -1,4 +1,44 @@ package com.tikitaka.naechinso.domain.match.entity; -public class Match { +import com.fasterxml.jackson.annotation.JsonIgnore; +import com.tikitaka.naechinso.domain.match.constant.MatchStatus; +import com.tikitaka.naechinso.domain.member.entity.Member; +import com.tikitaka.naechinso.global.config.entity.BaseEntity; +import lombok.*; + +import javax.persistence.*; +import java.util.ArrayList; +import java.util.List; + +@Entity +@Table(name = "match") +@Getter +@Builder +@AllArgsConstructor +@NoArgsConstructor +@ToString(exclude = {"fromMember", "toMember"}) +@EqualsAndHashCode +public class Match extends BaseEntity { + @Id + @Column(name = "mat_id") + @GeneratedValue + private Long id; + + @Column(name = "mat_status") + @Enumerated(EnumType.STRING) + @Builder.Default + private MatchStatus status = MatchStatus.WAIT; + + /* 호감을 보내는 사람 */ + @ManyToOne(fetch = FetchType.LAZY) + @JoinColumn(name = "mem_from_id") + @JsonIgnore + private Member fromMember; + + /* 호감을 받는 사람 */ + @ManyToOne(fetch = FetchType.LAZY) + @JoinColumn(name = "mem_to_id") + @JsonIgnore + private Member toMember; + } diff --git a/src/main/java/com/tikitaka/naechinso/domain/member/dto/MemberDetailUpdateRequestDTO.java b/src/main/java/com/tikitaka/naechinso/domain/member/dto/MemberDetailUpdateRequestDTO.java new file mode 100644 index 0000000..15f65cf --- /dev/null +++ b/src/main/java/com/tikitaka/naechinso/domain/member/dto/MemberDetailUpdateRequestDTO.java @@ -0,0 +1,66 @@ +package com.tikitaka.naechinso.domain.member.dto; + +import com.tikitaka.naechinso.domain.member.constant.Gender; +import com.tikitaka.naechinso.global.annotation.Enum; +import io.swagger.annotations.ApiModelProperty; +import lombok.*; +import org.hibernate.validator.constraints.Length; + +import javax.validation.constraints.*; +import java.util.List; + +/** + * 상세 정보의 변경을 위한 DTO 입니다 + * @author gengminy 221011 + * */ +@AllArgsConstructor +@NoArgsConstructor +@Getter +@Builder +@ToString +public class MemberDetailUpdateRequestDTO { + @ApiModelProperty(example = "180") + @Positive(message = "키는 양수여야 합니다") + private int height; + + @ApiModelProperty(example = "서울시 강남구") + @NotBlank(message = "주소 정보를 입력해야 합니다") + private String address; + + @ApiModelProperty(example = "무교") + @NotBlank(message = "종교 정보를 입력해야 합니다") + private String religion; + + @ApiModelProperty(example = "1병") + @NotBlank(message = "음주 정보를 입력해야 합니다") + private String drink; + + @ApiModelProperty(example = "비흡연자") + @NotBlank(message = "흡연 정보를 입력해야 합니다") + private String smoke; + + @ApiModelProperty(example = "ESTJ") + @Length(max = 4, message = "올바른 MBTI 정보를 입력하세요") + private String mbti; + + @ApiModelProperty(example = "직관적") + @NotBlank(message = "성격 정보를 입력해야 합니다") + private String personality; + + @ApiModelProperty(example = "반갑습니다") + @NotBlank(message = "자기 소개를 입력해야 합니다") + private String introduce; + + @ApiModelProperty(example = "코딩") + @NotBlank(message = "취미 정보를 입력해야 합니다") + private String hobby; + + @ApiModelProperty(example = "헌신적임") + @NotBlank(message = "연애 스타일을 입력해야 합니다") + private String style; + + @ApiModelProperty(example = "[\"img1\", \"img2\", \"img3\"]") + @Size(min = 3, max = 3, message = "사진 3장을 업로드해야 합니다") + @NotNull + private List images; +} diff --git a/src/main/java/com/tikitaka/naechinso/domain/member/entity/Member.java b/src/main/java/com/tikitaka/naechinso/domain/member/entity/Member.java index db60306..95e9db1 100644 --- a/src/main/java/com/tikitaka/naechinso/domain/member/entity/Member.java +++ b/src/main/java/com/tikitaka/naechinso/domain/member/entity/Member.java @@ -1,12 +1,14 @@ package com.tikitaka.naechinso.domain.member.entity; import com.fasterxml.jackson.annotation.JsonIgnore; +import com.tikitaka.naechinso.domain.match.entity.Match; import com.tikitaka.naechinso.domain.member.constant.Gender; import com.tikitaka.naechinso.domain.member.constant.Role; import com.tikitaka.naechinso.domain.member.dto.MemberUpdateCommonRequestDTO; import com.tikitaka.naechinso.domain.member.dto.MemberUpdateEduRequestDTO; import com.tikitaka.naechinso.domain.member.dto.MemberUpdateJobRequestDTO; import com.tikitaka.naechinso.domain.pending.entity.Pending; +import com.tikitaka.naechinso.domain.point.entity.Point; import com.tikitaka.naechinso.domain.recommend.entity.Recommend; import com.tikitaka.naechinso.global.config.entity.BaseEntity; import com.tikitaka.naechinso.global.error.ErrorCode; @@ -120,6 +122,20 @@ public class Member extends BaseEntity { @JsonIgnore private List pending = new ArrayList<>(); + //포인트 내역 + @OneToMany(mappedBy = "member") + @JsonIgnore + private List points = new ArrayList<>(); + + //내가 보낸 호감 내역 + @OneToMany(mappedBy = "fromMember") + @JsonIgnore + private List matchesTo = new ArrayList<>(); + + //내가 받은 호감 내역 + @OneToMany(mappedBy = "toMember") + @JsonIgnore + private List matchesFrom = new ArrayList<>(); //내가 소개해준 사람들 //mapped by 에는 연관관계 엔티티의 필드명을 적어줌 diff --git a/src/main/java/com/tikitaka/naechinso/domain/member/entity/MemberDetail.java b/src/main/java/com/tikitaka/naechinso/domain/member/entity/MemberDetail.java index c1b6689..fb7c1d6 100644 --- a/src/main/java/com/tikitaka/naechinso/domain/member/entity/MemberDetail.java +++ b/src/main/java/com/tikitaka/naechinso/domain/member/entity/MemberDetail.java @@ -79,10 +79,6 @@ public class MemberDetail extends BaseEntity { @Builder.Default private Long point = 0L; - // 포인트 내역 - @OneToMany(mappedBy = "member") - private List points = new ArrayList<>(); - // MemberDetail 을 소유한 Member 와 연결 // Member Entity 와 1:1 조인 // Member PK 그대로 사용 diff --git a/src/main/java/com/tikitaka/naechinso/domain/point/entity/Point.java b/src/main/java/com/tikitaka/naechinso/domain/point/entity/Point.java index 86ffcce..57bda79 100644 --- a/src/main/java/com/tikitaka/naechinso/domain/point/entity/Point.java +++ b/src/main/java/com/tikitaka/naechinso/domain/point/entity/Point.java @@ -36,5 +36,5 @@ public class Point extends BaseEntity { @ManyToOne(fetch = FetchType.LAZY) @JoinColumn(name = "mem_id") - private MemberDetail member; + private Member member; } From 9a0e4b2ec2728a1f536105f36a9b7928177676ae Mon Sep 17 00:00:00 2001 From: gengminy Date: Thu, 13 Oct 2022 19:57:01 +0900 Subject: [PATCH 27/72] =?UTF-8?q?:hammer:=20fix(recommend):=20=EC=B6=94?= =?UTF-8?q?=EC=B2=9C=20=ED=95=84=EB=93=9C=20=EB=88=84=EB=9D=BD=20=EB=B6=80?= =?UTF-8?q?=EB=B6=84=20=EC=B6=94=EA=B0=80=20#39?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../naechinso/domain/TestController.java | 8 +- .../tikitaka/naechinso/domain/card/todo.md | 12 ++ .../domain/match/MatchController.java | 22 ++- .../domain/match/MatchRepository.java | 7 + .../naechinso/domain/match/MatchService.java | 31 +++- .../match/dto/MatchListResponseDTO.java | 45 ++++++ .../domain/match/dto/MatchResponseDTO.java | 29 ++++ .../naechinso/domain/match/entity/Match.java | 2 - .../domain/member/MemberController.java | 20 ++- .../domain/member/MemberService.java | 10 ++ .../dto/MemberOppositeProfileResponseDTO.java | 139 ++++++++++++++++++ .../domain/member/entity/Member.java | 2 + .../domain/pending/PendingController.java | 9 ++ .../domain/pending/PendingService.java | 5 + .../dto/RecommendAcceptRequestDTO.java | 8 +- .../dto/RecommendBySenderRequestDTO.java | 4 + ...ommendMemberAcceptAndUpdateRequestDTO.java | 7 +- .../dto/RecommendMemberAcceptRequestDTO.java | 6 +- .../recommend/dto/RecommendResponseDTO.java | 3 + .../domain/recommend/entity/Recommend.java | 4 + 20 files changed, 349 insertions(+), 24 deletions(-) create mode 100644 src/main/java/com/tikitaka/naechinso/domain/card/todo.md create mode 100644 src/main/java/com/tikitaka/naechinso/domain/match/dto/MatchListResponseDTO.java create mode 100644 src/main/java/com/tikitaka/naechinso/domain/member/dto/MemberOppositeProfileResponseDTO.java diff --git a/src/main/java/com/tikitaka/naechinso/domain/TestController.java b/src/main/java/com/tikitaka/naechinso/domain/TestController.java index a6a77f1..aa9ed40 100644 --- a/src/main/java/com/tikitaka/naechinso/domain/TestController.java +++ b/src/main/java/com/tikitaka/naechinso/domain/TestController.java @@ -218,8 +218,8 @@ public CommonApiResponse createTwoRegularMember() { "01012345678", MemberCommonJoinRequestDTO.builder() .age(25) - .gender(Gender.M) - .name("닉") + .gender(Gender.W) + .name("아이유") .acceptsInfo(true) .acceptsLocation(true) .acceptsMarketing(true) @@ -240,7 +240,7 @@ public CommonApiResponse createTwoRegularMember() { MemberCommonJoinRequestDTO.builder() .age(28) .gender(Gender.M) - .name("박스") + .name("지드래곤") .acceptsInfo(true) .acceptsLocation(true) .acceptsMarketing(true) @@ -261,6 +261,7 @@ public CommonApiResponse createTwoRegularMember() { .age(25) .period("3달") .appeal("멋짐") + .appealDetail("짱짱짱 멋짐") .phone("01012345678") .meet("테스트중에") .personality("착함") @@ -274,6 +275,7 @@ public CommonApiResponse createTwoRegularMember() { .age(25) .period("1년") .appeal("짱") + .appealDetail("짱짱짱 멋짐") .phone("01011111111") .meet("CMC에서") .personality("최고") diff --git a/src/main/java/com/tikitaka/naechinso/domain/card/todo.md b/src/main/java/com/tikitaka/naechinso/domain/card/todo.md new file mode 100644 index 0000000..544f9d3 --- /dev/null +++ b/src/main/java/com/tikitaka/naechinso/domain/card/todo.md @@ -0,0 +1,12 @@ +# TODO + +매칭과는 별개로 채팅창에서 +랜덤 상대를 추천해주는 것에 대해 구현해야함 + +랜덤 카드 추천은 하루에 세 개 + +둘 중 한명이 호감을 보내면 매칭 내역으로 보냄 + +만약 이미 유효한 매칭 내역에 있는 상대라면 번호 오픈 + +매칭 상태에서 한명만 결제를 해도 번호 오픈 \ No newline at end of file diff --git a/src/main/java/com/tikitaka/naechinso/domain/match/MatchController.java b/src/main/java/com/tikitaka/naechinso/domain/match/MatchController.java index 1f602b6..0146d51 100644 --- a/src/main/java/com/tikitaka/naechinso/domain/match/MatchController.java +++ b/src/main/java/com/tikitaka/naechinso/domain/match/MatchController.java @@ -1,9 +1,17 @@ package com.tikitaka.naechinso.domain.match; +import com.tikitaka.naechinso.domain.match.dto.MatchListResponseDTO; +import com.tikitaka.naechinso.domain.match.dto.MatchResponseDTO; +import com.tikitaka.naechinso.domain.member.entity.Member; +import com.tikitaka.naechinso.global.annotation.AuthMember; +import com.tikitaka.naechinso.global.config.CommonApiResponse; +import io.swagger.annotations.ApiOperation; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; +import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; +import springfox.documentation.annotations.ApiIgnore; @Slf4j @RestController @@ -11,11 +19,11 @@ @RequiredArgsConstructor public class MatchController { private final MatchService matchService; -// @GetMapping -// @ApiOperation(value = "자신의 매칭 정보를 가져온다 (AccessToken)") -// public CommonApiResponse getAllMatchByMember( -// @ApiIgnore @AuthMember Member member -// ) { -// return CommonApiResponse.of(member.toString()); -// } + @GetMapping + @ApiOperation(value = "매칭페이지에 진입 시 자신의 모든 매칭 정보를 가져온다 (AccessToken)") + public CommonApiResponse getAllMatchByMember( + @ApiIgnore @AuthMember Member member + ) { + return CommonApiResponse.of(matchService.findAllByMember(member)); + } } diff --git a/src/main/java/com/tikitaka/naechinso/domain/match/MatchRepository.java b/src/main/java/com/tikitaka/naechinso/domain/match/MatchRepository.java index 423ff16..0ac6ee2 100644 --- a/src/main/java/com/tikitaka/naechinso/domain/match/MatchRepository.java +++ b/src/main/java/com/tikitaka/naechinso/domain/match/MatchRepository.java @@ -1,9 +1,16 @@ package com.tikitaka.naechinso.domain.match; import com.tikitaka.naechinso.domain.match.entity.Match; +import com.tikitaka.naechinso.domain.member.entity.Member; import org.springframework.data.jpa.repository.JpaRepository; import org.springframework.stereotype.Repository; +import java.util.List; +import java.util.Optional; + @Repository public interface MatchRepository extends JpaRepository { + + List findAllByFromMember(Member member); + List findAllByToMember(Member member); } diff --git a/src/main/java/com/tikitaka/naechinso/domain/match/MatchService.java b/src/main/java/com/tikitaka/naechinso/domain/match/MatchService.java index 8723378..887a138 100644 --- a/src/main/java/com/tikitaka/naechinso/domain/match/MatchService.java +++ b/src/main/java/com/tikitaka/naechinso/domain/match/MatchService.java @@ -1,16 +1,16 @@ package com.tikitaka.naechinso.domain.match; +import com.tikitaka.naechinso.domain.match.dto.MatchListResponseDTO; +import com.tikitaka.naechinso.domain.match.entity.Match; import com.tikitaka.naechinso.domain.member.MemberService; import com.tikitaka.naechinso.domain.member.entity.Member; -import com.tikitaka.naechinso.global.annotation.AuthMember; -import com.tikitaka.naechinso.global.config.CommonApiResponse; -import io.swagger.annotations.ApiOperation; +import com.tikitaka.naechinso.global.error.exception.NotFoundException; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; -import org.springframework.web.bind.annotation.GetMapping; -import springfox.documentation.annotations.ApiIgnore; + +import java.util.List; @Slf4j @Service @@ -19,4 +19,25 @@ public class MatchService { private final MatchRepository matchRepository; private final MemberService memberService; + + + public MatchListResponseDTO findAllByMember(Member authMember) { + return MatchListResponseDTO.of(authMember); + } + + + /** 모든 매칭 엔티티 인스턴스를 가져온다 */ + public List findAll() { + return matchRepository.findAll(); + } + + /** 호감을 보내는 쪽 사람의 매칭 정보를 모두 가져온다 */ + public List findAllMatchBySender(Member member) { + return matchRepository.findAllByFromMember(member); + } + + /** 호감을 받는 쪽 사람의 매칭 정보를 모두 가져온다 */ + public List findAllMatchByToReceiver(Member member) { + return matchRepository.findAllByToMember(member); + } } diff --git a/src/main/java/com/tikitaka/naechinso/domain/match/dto/MatchListResponseDTO.java b/src/main/java/com/tikitaka/naechinso/domain/match/dto/MatchListResponseDTO.java new file mode 100644 index 0000000..b46a8fd --- /dev/null +++ b/src/main/java/com/tikitaka/naechinso/domain/match/dto/MatchListResponseDTO.java @@ -0,0 +1,45 @@ +package com.tikitaka.naechinso.domain.match.dto; + +import com.tikitaka.naechinso.domain.member.entity.Member; +import com.tikitaka.naechinso.domain.recommend.dto.RecommendListResponseDTO; +import com.tikitaka.naechinso.domain.recommend.dto.RecommendResponseDTO; +import lombok.*; + +import java.util.ArrayList; +import java.util.List; +import java.util.stream.Collectors; + +@AllArgsConstructor +@NoArgsConstructor +@Getter +@Builder +@ToString +public class MatchListResponseDTO { + //내가 보낸 호감 + List matchesTo = new ArrayList<>(); + //내가 받은 호감 + List matchesFrom = new ArrayList<>(); + //남은 랜덤 매칭 카드 횟수 +// matching card + + + public static MatchListResponseDTO of(Member member) { + List matchesToList = new ArrayList<>(); + List matchesFromList = new ArrayList<>(); + + if (member.getMatchesTo() != null) { + matchesToList = member.getMatchesTo().stream().map(MatchResponseDTO::of).collect(Collectors.toList()); + } + + if (member.getMatchesFrom() != null) { + matchesFromList = member.getMatchesFrom().stream().map(MatchResponseDTO::of).collect(Collectors.toList()); + } + + return MatchListResponseDTO.builder() + .matchesFrom(matchesFromList) + .matchesTo(matchesToList) + .build(); + } + + +} diff --git a/src/main/java/com/tikitaka/naechinso/domain/match/dto/MatchResponseDTO.java b/src/main/java/com/tikitaka/naechinso/domain/match/dto/MatchResponseDTO.java index c797f07..d537872 100644 --- a/src/main/java/com/tikitaka/naechinso/domain/match/dto/MatchResponseDTO.java +++ b/src/main/java/com/tikitaka/naechinso/domain/match/dto/MatchResponseDTO.java @@ -1,5 +1,10 @@ package com.tikitaka.naechinso.domain.match.dto; +import com.tikitaka.naechinso.domain.match.constant.MatchStatus; +import com.tikitaka.naechinso.domain.match.entity.Match; +import com.tikitaka.naechinso.global.error.ErrorCode; +import com.tikitaka.naechinso.global.error.exception.BadRequestException; +import com.tikitaka.naechinso.global.error.exception.NotFoundException; import lombok.*; @AllArgsConstructor @@ -8,4 +13,28 @@ @Builder @ToString public class MatchResponseDTO { + + private Long id; + + private MatchStatus status; + + private Long fromMemberId; + + private Long toMemberId; + + private String createdAt; + + public static MatchResponseDTO of(Match match) { + if (match.getFromMember() == null || match.getToMember() == null) { + throw new NotFoundException(ErrorCode.USER_NOT_FOUND); + } + + return MatchResponseDTO.builder() + .id(match.getId()) + .status(match.getStatus()) + .fromMemberId(match.getFromMember().getId()) + .toMemberId(match.getToMember().getId()) + .createdAt(match.getCreatedAt().toString()) + .build(); + } } diff --git a/src/main/java/com/tikitaka/naechinso/domain/match/entity/Match.java b/src/main/java/com/tikitaka/naechinso/domain/match/entity/Match.java index b1f08ae..0b91abd 100644 --- a/src/main/java/com/tikitaka/naechinso/domain/match/entity/Match.java +++ b/src/main/java/com/tikitaka/naechinso/domain/match/entity/Match.java @@ -7,8 +7,6 @@ import lombok.*; import javax.persistence.*; -import java.util.ArrayList; -import java.util.List; @Entity @Table(name = "match") diff --git a/src/main/java/com/tikitaka/naechinso/domain/member/MemberController.java b/src/main/java/com/tikitaka/naechinso/domain/member/MemberController.java index 927ca3f..a2b4800 100644 --- a/src/main/java/com/tikitaka/naechinso/domain/member/MemberController.java +++ b/src/main/java/com/tikitaka/naechinso/domain/member/MemberController.java @@ -27,8 +27,6 @@ public class MemberController { private final MemberService memberService; private final JwtTokenProvider jwtTokenService; - - @GetMapping @ApiOperation(value = "유저 자신의 모든 정보를 가져온다 (AccessToken)") public CommonApiResponse getMyInformation( @@ -37,6 +35,24 @@ public CommonApiResponse getMyInformation( return CommonApiResponse.of(memberService.readCommonMember(member)); } + @GetMapping("/{id}") + @ApiOperation(value = "고유 아이디의 유저를 가져온다 (AccessToken)") + public CommonApiResponse getMemberById( + @PathVariable("id") Long id +// @ApiIgnore @AuthMember Member member + ) { + return CommonApiResponse.of(MemberCommonResponseDTO.of(memberService.findById(id))); + } + + @GetMapping("/{id}/profile") + @ApiOperation(value = "고유 아이디의 유저 프로필과 추천인 정보를 가져온다 (AccessToken)") + public CommonApiResponse getMemberProfileById( + @PathVariable("id") Long id, + @ApiIgnore @AuthMember Member member + ) { + return CommonApiResponse.of(memberService.readOppositeMemberDetailAndRecommendById(id)); + } + @GetMapping("/detail") @ApiOperation(value = "회원가입 세부 정보를 가져온다 (AccessToken)") public CommonApiResponse getMemberDetail( diff --git a/src/main/java/com/tikitaka/naechinso/domain/member/MemberService.java b/src/main/java/com/tikitaka/naechinso/domain/member/MemberService.java index 159c351..cd37599 100644 --- a/src/main/java/com/tikitaka/naechinso/domain/member/MemberService.java +++ b/src/main/java/com/tikitaka/naechinso/domain/member/MemberService.java @@ -88,6 +88,16 @@ public MemberDetailResponseDTO readDetail(Member member) { return MemberDetailResponseDTO.of(member); } + + /** + * 랜덤 추천받은 상대의 프로필 카드를 가져오는 서비스 로직 + * @// TODO: 2022/10/13 서로 연관 있는 상태가 아닐때 접근할 수 없도록 해야함 + * */ + public MemberOppositeProfileResponseDTO readOppositeMemberDetailAndRecommendById(Long id) { + Member oppositeMember = findById(id); + return MemberOppositeProfileResponseDTO.of(oppositeMember); + } + public MemberDetailResponseDTO createDetail(Member authMember, MemberDetailJoinRequestDTO dto) { //영속성 유지를 위한 fetch Member member = findByMember(authMember); diff --git a/src/main/java/com/tikitaka/naechinso/domain/member/dto/MemberOppositeProfileResponseDTO.java b/src/main/java/com/tikitaka/naechinso/domain/member/dto/MemberOppositeProfileResponseDTO.java new file mode 100644 index 0000000..7c925b0 --- /dev/null +++ b/src/main/java/com/tikitaka/naechinso/domain/member/dto/MemberOppositeProfileResponseDTO.java @@ -0,0 +1,139 @@ +package com.tikitaka.naechinso.domain.member.dto; + +import com.tikitaka.naechinso.domain.member.constant.Gender; +import com.tikitaka.naechinso.domain.member.constant.Role; +import com.tikitaka.naechinso.domain.member.entity.Member; +import com.tikitaka.naechinso.domain.member.entity.MemberDetail; +import com.tikitaka.naechinso.domain.recommend.entity.Recommend; +import com.tikitaka.naechinso.global.error.ErrorCode; +import com.tikitaka.naechinso.global.error.exception.BadRequestException; +import com.tikitaka.naechinso.global.error.exception.NotFoundException; +import lombok.*; +import org.springframework.security.core.parameters.P; + +import java.util.List; + +/** + * 상대방 프로필에 대한 정보를 반환하는 DTO 입니다 + * @author gengminy 221013 + * */ +@AllArgsConstructor +@NoArgsConstructor +@Getter +@Builder +@ToString +public class MemberOppositeProfileResponseDTO { + + private List images; + private String name; + private int age; + + private String address; + private Gender gender; + + private String jobName; + private String jobPart; + private String jobLocation; + + private String eduName; + private String eduMajor; + private String eduLevel; + + private String personality; + private String religion; + private int height; + private String smoke; + private String drink; + + private String hobby; + private String style; + private String introduce; + + + private String mbti; + + private Recommendation recommend; + + public static MemberOppositeProfileResponseDTO of(Member member) { + MemberDetail detail = member.getDetail(); + //디테일 없는 유저로 시도 + if (detail == null) { + throw new NotFoundException(ErrorCode.USER_NOT_FOUND); + } + + //추천받은 적 없는 유저를 가져오는 것을 시도 + if (member.getRecommendReceived() == null){ + throw new NotFoundException(ErrorCode.RECOMMEND_NOT_FOUND); + } + + for (Recommend recommend: member.getRecommendReceived()) { + //추천 상태 검증 + if (recommend.getSender() != null && recommend.getReceiver() != null) { + return MemberOppositeProfileResponseDTO.builder() + .images(detail.getImages()) + .name(hideName(member.getName())) + .age(member.getAge()) + .address(detail.getAddress()) + .jobName(member.getJobName()) + .jobPart(member.getJobPart()) + .jobLocation(member.getJobLocation()) + .eduName(member.getEduName()) + .eduMajor(member.getEduMajor()) + .eduLevel(member.getEduLevel()) + .gender(member.getGender()) + .personality(detail.getPersonality()) + .religion(detail.getReligion()) + .height(detail.getHeight()) + .smoke(detail.getSmoke()) + .drink(detail.getDrink()) + .hobby(detail.getHobby()) + .style(detail.getStyle()) + .introduce(detail.getIntroduce()) + .mbti(detail.getMbti()) + .recommend(Recommendation.of(recommend)) + .build(); + + } + } + throw new NotFoundException(ErrorCode.RECOMMEND_NOT_FOUND); + } + + + @AllArgsConstructor + @NoArgsConstructor + @Getter + @Builder + @ToString + private static class Recommendation { + private String name; + private Gender gender; + private String appeal; + private String appealDetail; + private String meet; + private String period; + + public static Recommendation of(Recommend recommend) { + return Recommendation.builder() + .name(hideName(recommend.getSenderName())) + .gender(recommend.getSenderGender()) + .appeal(recommend.getReceiverAppeal()) + .appealDetail(recommend.getReceiverAppealDetail()) + .meet(recommend.getReceiverMeet()) + .period(recommend.getReceiverPeriod()) + .build(); + } + } + + private static String hideName(String name) { + if (name.length() == 1) { + return "*"; + } else if (name.length() == 2) { + return name.charAt(0) + "*"; + } else if (name.length() > 2) { + return name.charAt(0) + + "*".repeat(name.length() - 2) + + name.charAt(name.length() - 1); + } + return name; + } +} diff --git a/src/main/java/com/tikitaka/naechinso/domain/member/entity/Member.java b/src/main/java/com/tikitaka/naechinso/domain/member/entity/Member.java index 95e9db1..d75f5c5 100644 --- a/src/main/java/com/tikitaka/naechinso/domain/member/entity/Member.java +++ b/src/main/java/com/tikitaka/naechinso/domain/member/entity/Member.java @@ -130,11 +130,13 @@ public class Member extends BaseEntity { //내가 보낸 호감 내역 @OneToMany(mappedBy = "fromMember") @JsonIgnore + @Builder.Default private List matchesTo = new ArrayList<>(); //내가 받은 호감 내역 @OneToMany(mappedBy = "toMember") @JsonIgnore + @Builder.Default private List matchesFrom = new ArrayList<>(); //내가 소개해준 사람들 diff --git a/src/main/java/com/tikitaka/naechinso/domain/pending/PendingController.java b/src/main/java/com/tikitaka/naechinso/domain/pending/PendingController.java index e02b559..df79b68 100644 --- a/src/main/java/com/tikitaka/naechinso/domain/pending/PendingController.java +++ b/src/main/java/com/tikitaka/naechinso/domain/pending/PendingController.java @@ -38,6 +38,15 @@ public CommonApiResponse> getAllPending( return CommonApiResponse.of(pendingService.findAll()); } + @GetMapping("/{id}") + @ApiOperation(value = "[Admin]고유 아이디에 해당하는 대기 정보를 가져온다 (AccessToken)") + public CommonApiResponse getPendingById( + @PathVariable("id") Long id, + @ApiIgnore @AuthMember Member adminMember + ) { + return CommonApiResponse.of(PendingFindResponseDTO.of(pendingService.findById(id))); + } + @PostMapping("/{id}/accept") @ApiOperation(value = "[Admin] 요청을 승인한다 (AccessToken)") public CommonApiResponse acceptPending( diff --git a/src/main/java/com/tikitaka/naechinso/domain/pending/PendingService.java b/src/main/java/com/tikitaka/naechinso/domain/pending/PendingService.java index 4a97154..5591af0 100644 --- a/src/main/java/com/tikitaka/naechinso/domain/pending/PendingService.java +++ b/src/main/java/com/tikitaka/naechinso/domain/pending/PendingService.java @@ -221,4 +221,9 @@ public List findAll() { return pendingRepository.findAll() .stream().map(PendingFindResponseDTO::of).collect(Collectors.toList()); } + + public Pending findById(Long id) { + return pendingRepository.findById(id) + .orElseThrow(() -> new NotFoundException(ErrorCode.PENDING_NOT_FOUND)); + } } diff --git a/src/main/java/com/tikitaka/naechinso/domain/recommend/dto/RecommendAcceptRequestDTO.java b/src/main/java/com/tikitaka/naechinso/domain/recommend/dto/RecommendAcceptRequestDTO.java index 3a5e54e..82be387 100644 --- a/src/main/java/com/tikitaka/naechinso/domain/recommend/dto/RecommendAcceptRequestDTO.java +++ b/src/main/java/com/tikitaka/naechinso/domain/recommend/dto/RecommendAcceptRequestDTO.java @@ -23,10 +23,14 @@ public class RecommendAcceptRequestDTO { @NotBlank(message = "친구의 성격 키워드를 입력해주세요") private String personality; - @ApiModelProperty(example = "짱") - @NotBlank(message = "친구의 매력을 입력해주세요") + @ApiModelProperty(example = "유머있는") + @NotBlank(message = "친구의 매력 키워드를 입력해주세요") private String appeal; + @ApiModelProperty(example = "짱짱짜짱 멋진 개발자입니다") + @NotBlank(message = "친구의 자세한 매력을 입력해주세요") + private String appealDetail; + @ApiModelProperty(example = "1년") @NotBlank(message = "만난 기간을 입력해주세요") private String period; diff --git a/src/main/java/com/tikitaka/naechinso/domain/recommend/dto/RecommendBySenderRequestDTO.java b/src/main/java/com/tikitaka/naechinso/domain/recommend/dto/RecommendBySenderRequestDTO.java index d097e26..95b7249 100644 --- a/src/main/java/com/tikitaka/naechinso/domain/recommend/dto/RecommendBySenderRequestDTO.java +++ b/src/main/java/com/tikitaka/naechinso/domain/recommend/dto/RecommendBySenderRequestDTO.java @@ -46,6 +46,10 @@ public class RecommendBySenderRequestDTO { @NotBlank(message = "친구의 매력을 입력해주세요") private String appeal; + @ApiModelProperty(example = "짱짱짜짱 멋진 개발자입니다") + @NotBlank(message = "친구의 자세한 매력을 입력해주세요") + private String appealDetail; + @ApiModelProperty(example = "1년") @NotBlank(message = "만난 기간을 입력해주세요") private String period; diff --git a/src/main/java/com/tikitaka/naechinso/domain/recommend/dto/RecommendMemberAcceptAndUpdateRequestDTO.java b/src/main/java/com/tikitaka/naechinso/domain/recommend/dto/RecommendMemberAcceptAndUpdateRequestDTO.java index 75606fc..e8cc324 100644 --- a/src/main/java/com/tikitaka/naechinso/domain/recommend/dto/RecommendMemberAcceptAndUpdateRequestDTO.java +++ b/src/main/java/com/tikitaka/naechinso/domain/recommend/dto/RecommendMemberAcceptAndUpdateRequestDTO.java @@ -41,11 +41,14 @@ public class RecommendMemberAcceptAndUpdateRequestDTO { private String personality; @ApiModelProperty(example = "짱") - @NotBlank(message = "친구의 매력을 입력해주세요") + @NotBlank(message = "친구의 매력 키워드를 입력해주세요") private String appeal; + @ApiModelProperty(example = "짱짱짜짱 멋진 개발자입니다") + @NotBlank(message = "친구의 자세한 매력을 입력해주세요") + private String appealDetail; + @ApiModelProperty(example = "1년") @NotBlank(message = "만난 기간을 입력해주세요") private String period; - } diff --git a/src/main/java/com/tikitaka/naechinso/domain/recommend/dto/RecommendMemberAcceptRequestDTO.java b/src/main/java/com/tikitaka/naechinso/domain/recommend/dto/RecommendMemberAcceptRequestDTO.java index b74575c..27330e1 100644 --- a/src/main/java/com/tikitaka/naechinso/domain/recommend/dto/RecommendMemberAcceptRequestDTO.java +++ b/src/main/java/com/tikitaka/naechinso/domain/recommend/dto/RecommendMemberAcceptRequestDTO.java @@ -23,9 +23,13 @@ public class RecommendMemberAcceptRequestDTO { private String personality; @ApiModelProperty(example = "짱") - @NotBlank(message = "친구의 매력을 입력해주세요") + @NotBlank(message = "친구의 매력 키워드를 입력해주세요") private String appeal; + @ApiModelProperty(example = "짱짱짜짱 멋진 개발자입니다") + @NotBlank(message = "친구의 자세한 매력을 입력해주세요") + private String appealDetail; + @ApiModelProperty(example = "1년") @NotBlank(message = "만난 기간을 입력해주세요") private String period; diff --git a/src/main/java/com/tikitaka/naechinso/domain/recommend/dto/RecommendResponseDTO.java b/src/main/java/com/tikitaka/naechinso/domain/recommend/dto/RecommendResponseDTO.java index 5a8ea66..e99b841 100644 --- a/src/main/java/com/tikitaka/naechinso/domain/recommend/dto/RecommendResponseDTO.java +++ b/src/main/java/com/tikitaka/naechinso/domain/recommend/dto/RecommendResponseDTO.java @@ -23,6 +23,8 @@ public class RecommendResponseDTO { private String appeal; + private String appealDetail; + private String period; private Long senderId; @@ -54,6 +56,7 @@ public static RecommendResponseDTO of(Recommend recommend) { .gender(recommend.getReceiverGender()) .meet(recommend.getReceiverMeet()) .appeal(recommend.getReceiverAppeal()) + .appealDetail(recommend.getReceiverAppealDetail()) .period(recommend.getReceiverPeriod()) .build(); } diff --git a/src/main/java/com/tikitaka/naechinso/domain/recommend/entity/Recommend.java b/src/main/java/com/tikitaka/naechinso/domain/recommend/entity/Recommend.java index b679a64..4318d5e 100644 --- a/src/main/java/com/tikitaka/naechinso/domain/recommend/entity/Recommend.java +++ b/src/main/java/com/tikitaka/naechinso/domain/recommend/entity/Recommend.java @@ -89,12 +89,16 @@ public class Recommend extends BaseEntity { @Column(name = "rec_appeal") private String receiverAppeal; + @Column(name = "rec_appeal_detail") + private String receiverAppealDetail; + @Column(name = "rec_period") private String receiverPeriod; public void update(RecommendAcceptRequestDTO requestDTO) { this.receiverAppeal = requestDTO.getAppeal(); + this.receiverAppealDetail = requestDTO.getAppealDetail(); this.receiverMeet = requestDTO.getMeet(); this.receiverPersonality = requestDTO.getPersonality(); this.receiverPeriod = requestDTO.getPeriod(); From 36207a27be2ae03d02147b85055c9d9f3f06448f Mon Sep 17 00:00:00 2001 From: gengminy Date: Mon, 17 Oct 2022 19:20:48 +0900 Subject: [PATCH 28/72] =?UTF-8?q?:rocket:=20feat(card):=20=EB=9E=9C?= =?UTF-8?q?=EB=8D=A4=20=EC=B6=94=EC=B2=9C=20=EC=B9=B4=EB=93=9C=20=EC=97=94?= =?UTF-8?q?=ED=8B=B0=ED=8B=B0=20=EC=83=9D=EC=84=B1=20=EB=B0=8F=20=EC=97=B0?= =?UTF-8?q?=EA=B4=80=EA=B4=80=EA=B3=84=20=EC=84=A4=EC=A0=95=20#41?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../naechinso/domain/TestController.java | 2 - .../naechinso/domain/card/CardController.java | 49 +++++++++++++++++++ .../naechinso/domain/card/CardRepository.java | 31 ++++++++++++ .../naechinso/domain/card/CardService.java | 45 +++++++++++++++++ .../card/dto/CardRefreshRequestDTO.java | 4 ++ .../domain/card/dto/CardResponseDTO.java | 32 ++++++++++++ .../naechinso/domain/card/entity/Card.java | 39 +++++++++++++++ .../domain/member/entity/Member.java | 5 ++ 8 files changed, 205 insertions(+), 2 deletions(-) create mode 100644 src/main/java/com/tikitaka/naechinso/domain/card/CardController.java create mode 100644 src/main/java/com/tikitaka/naechinso/domain/card/CardRepository.java create mode 100644 src/main/java/com/tikitaka/naechinso/domain/card/CardService.java create mode 100644 src/main/java/com/tikitaka/naechinso/domain/card/dto/CardRefreshRequestDTO.java create mode 100644 src/main/java/com/tikitaka/naechinso/domain/card/dto/CardResponseDTO.java create mode 100644 src/main/java/com/tikitaka/naechinso/domain/card/entity/Card.java diff --git a/src/main/java/com/tikitaka/naechinso/domain/TestController.java b/src/main/java/com/tikitaka/naechinso/domain/TestController.java index aa9ed40..737d9d1 100644 --- a/src/main/java/com/tikitaka/naechinso/domain/TestController.java +++ b/src/main/java/com/tikitaka/naechinso/domain/TestController.java @@ -12,12 +12,10 @@ import com.tikitaka.naechinso.domain.recommend.RecommendService; import com.tikitaka.naechinso.domain.recommend.dto.RecommendBySenderRequestDTO; import com.tikitaka.naechinso.domain.recommend.dto.RecommendResponseDTO; -import com.tikitaka.naechinso.domain.recommend.entity.Recommend; import com.tikitaka.naechinso.global.config.CommonApiResponse; import io.swagger.annotations.ApiOperation; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; -import org.springframework.transaction.annotation.Transactional; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.PathVariable; import org.springframework.web.bind.annotation.RequestMapping; diff --git a/src/main/java/com/tikitaka/naechinso/domain/card/CardController.java b/src/main/java/com/tikitaka/naechinso/domain/card/CardController.java new file mode 100644 index 0000000..d4166ff --- /dev/null +++ b/src/main/java/com/tikitaka/naechinso/domain/card/CardController.java @@ -0,0 +1,49 @@ +package com.tikitaka.naechinso.domain.card; + +import com.tikitaka.naechinso.domain.match.MatchService; +import com.tikitaka.naechinso.domain.match.dto.MatchListResponseDTO; +import com.tikitaka.naechinso.domain.member.entity.Member; +import com.tikitaka.naechinso.global.annotation.AuthMember; +import com.tikitaka.naechinso.global.config.CommonApiResponse; +import io.swagger.annotations.ApiOperation; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.springframework.stereotype.Controller; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; +import springfox.documentation.annotations.ApiIgnore; + +@Slf4j +@RestController +@RequestMapping("/card") +@RequiredArgsConstructor +public class CardController { + private final CardService cardService; + + @GetMapping + @ApiOperation(value = "자신이 소유한 모든 카드를 가져온다 (AccessToken)") + public CommonApiResponse getAllCardsByMember( + @ApiIgnore @AuthMember Member member + ) { + return CommonApiResponse.of(cardService.findAllByMember(member)); + } + + @GetMapping("/find") + @ApiOperation(value = "[Admin]존재하는 모든 카드를 가져온다 (AccessToken)") + public CommonApiResponse getAllCards( + @ApiIgnore @AuthMember Member member + ) { + return CommonApiResponse.of(cardService.findAll()); + } + + + @PostMapping + @ApiOperation(value = "새로운 카드를 하나 생성한다 (AccessToken)") + public CommonApiResponse createCardByMember( + @ApiIgnore @AuthMember Member member + ) { + return CommonApiResponse.of(cardService.createCard(member)); + } +} diff --git a/src/main/java/com/tikitaka/naechinso/domain/card/CardRepository.java b/src/main/java/com/tikitaka/naechinso/domain/card/CardRepository.java new file mode 100644 index 0000000..b2f0dc9 --- /dev/null +++ b/src/main/java/com/tikitaka/naechinso/domain/card/CardRepository.java @@ -0,0 +1,31 @@ +package com.tikitaka.naechinso.domain.card; + +import com.tikitaka.naechinso.domain.card.dto.CardResponseDTO; +import com.tikitaka.naechinso.domain.card.entity.Card; +import com.tikitaka.naechinso.domain.member.entity.Member; +import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.data.jpa.repository.Query; +import org.springframework.stereotype.Repository; +import java.time.LocalDateTime; + +import java.util.List; + +@Repository +public interface CardRepository extends JpaRepository { + int countByIsActive(boolean isActive); + + List findAllByMember(Member member); + + @Query("select new com.tikitaka.naechinso.domain.card.dto.CardResponseDTO(c.targetId, c.isActive, c.createdAt) " + + "from Card c " + + "join c.member m " + + "where m = :member") + List findAllDTOByMember(Member member); + + @Query("select new com.tikitaka.naechinso.domain.card.dto.CardResponseDTO(c.targetId, c.isActive, c.createdAt) " + + "from Card c " + + "join c.member m") + List findAllDTO(); + + +} diff --git a/src/main/java/com/tikitaka/naechinso/domain/card/CardService.java b/src/main/java/com/tikitaka/naechinso/domain/card/CardService.java new file mode 100644 index 0000000..c3aea82 --- /dev/null +++ b/src/main/java/com/tikitaka/naechinso/domain/card/CardService.java @@ -0,0 +1,45 @@ +package com.tikitaka.naechinso.domain.card; + +import com.tikitaka.naechinso.domain.card.dto.CardResponseDTO; +import com.tikitaka.naechinso.domain.card.entity.Card; +import com.tikitaka.naechinso.domain.member.MemberService; +import com.tikitaka.naechinso.domain.member.entity.Member; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +import java.util.List; + +@Slf4j +@Service +@RequiredArgsConstructor +public class CardService { + + private final CardRepository cardRepository; + private final MemberService memberService; + + public CardResponseDTO createCard(Member authMember) { + + Member member = memberService.findByMember(authMember); + + Card newCard = Card.builder() + .member(member) + .targetId(3L) + .build(); + + cardRepository.save(newCard); + + return CardResponseDTO.of(newCard); + } + + public List findAllByMember(Member member) { + return cardRepository.findAllDTOByMember(member); + } + + public List findAll() { + return cardRepository.findAllDTO(); + } + + +} diff --git a/src/main/java/com/tikitaka/naechinso/domain/card/dto/CardRefreshRequestDTO.java b/src/main/java/com/tikitaka/naechinso/domain/card/dto/CardRefreshRequestDTO.java new file mode 100644 index 0000000..7f7e69d --- /dev/null +++ b/src/main/java/com/tikitaka/naechinso/domain/card/dto/CardRefreshRequestDTO.java @@ -0,0 +1,4 @@ +package com.tikitaka.naechinso.domain.card.dto; + +public class CardRefreshRequestDTO { +} diff --git a/src/main/java/com/tikitaka/naechinso/domain/card/dto/CardResponseDTO.java b/src/main/java/com/tikitaka/naechinso/domain/card/dto/CardResponseDTO.java new file mode 100644 index 0000000..2996bc0 --- /dev/null +++ b/src/main/java/com/tikitaka/naechinso/domain/card/dto/CardResponseDTO.java @@ -0,0 +1,32 @@ +package com.tikitaka.naechinso.domain.card.dto; + +import com.tikitaka.naechinso.domain.card.entity.Card; +import com.tikitaka.naechinso.domain.match.constant.MatchStatus; +import lombok.*; + +import java.time.LocalDateTime; + +@NoArgsConstructor +@AllArgsConstructor +@Getter +@Builder +@ToString +public class CardResponseDTO { + private Long targetId; + private Boolean isActive; + private String createdAt; + + public static CardResponseDTO of(Card card) { + return CardResponseDTO.builder() + .targetId(card.getTargetId()) + .isActive(card.getIsActive()) + .createdAt(card.getCreatedAt().toString()) + .build(); + } + + public CardResponseDTO(Long id, Boolean isActive, LocalDateTime createdAt){ + this.targetId = id; + this.isActive = isActive; + this.createdAt = createdAt.toString(); + } +} diff --git a/src/main/java/com/tikitaka/naechinso/domain/card/entity/Card.java b/src/main/java/com/tikitaka/naechinso/domain/card/entity/Card.java new file mode 100644 index 0000000..1b551e1 --- /dev/null +++ b/src/main/java/com/tikitaka/naechinso/domain/card/entity/Card.java @@ -0,0 +1,39 @@ +package com.tikitaka.naechinso.domain.card.entity; + +import com.fasterxml.jackson.annotation.JsonIgnore; +import com.tikitaka.naechinso.domain.member.entity.Member; +import com.tikitaka.naechinso.global.config.entity.BaseEntity; +import lombok.*; + +import javax.persistence.*; + +/** + * 멤버 공통 정보를 담당하는 엔티티입니다 + * @author gengminy 220924 + * */ +@Entity +@Table(name = "card") +@Getter +@Builder +@AllArgsConstructor +@NoArgsConstructor +@ToString +@EqualsAndHashCode +public class Card extends BaseEntity { + @Id + @Column(name = "car_id") + @GeneratedValue(strategy = GenerationType.IDENTITY) + private Long id; + + @ManyToOne(fetch = FetchType.LAZY) + @JoinColumn(name = "mem_id") + @JsonIgnore + private Member member; + + @Column(name = "car_target_id") + private Long targetId; + + @Column(name = "car_is_active") + @Builder.Default + private Boolean isActive = false; +} diff --git a/src/main/java/com/tikitaka/naechinso/domain/member/entity/Member.java b/src/main/java/com/tikitaka/naechinso/domain/member/entity/Member.java index d75f5c5..7eb9875 100644 --- a/src/main/java/com/tikitaka/naechinso/domain/member/entity/Member.java +++ b/src/main/java/com/tikitaka/naechinso/domain/member/entity/Member.java @@ -1,6 +1,7 @@ package com.tikitaka.naechinso.domain.member.entity; import com.fasterxml.jackson.annotation.JsonIgnore; +import com.tikitaka.naechinso.domain.card.entity.Card; import com.tikitaka.naechinso.domain.match.entity.Match; import com.tikitaka.naechinso.domain.member.constant.Gender; import com.tikitaka.naechinso.domain.member.constant.Role; @@ -150,6 +151,10 @@ public class Member extends BaseEntity { @JsonIgnore //순환참조 방지, 엔티티 프로퍼티 가려줌 private List recommendReceived = new ArrayList<>(); + @OneToMany(mappedBy = "member", cascade = CascadeType.ALL) + @JsonIgnore + private List cards; + public void setDetail(MemberDetail memberDetail) { this.detail = memberDetail; From a9ea86007fa1edb767631372519b0aed4c505457 Mon Sep 17 00:00:00 2001 From: gengminy Date: Tue, 18 Oct 2022 15:47:12 +0900 Subject: [PATCH 29/72] =?UTF-8?q?:rocket:=20feat(card):=20=EB=8B=A4?= =?UTF-8?q?=EB=A5=B8=20=EC=84=B1=EB=B3=84=20=EC=9C=A0=EC=A0=80=20=EC=A4=91?= =?UTF-8?q?=EB=B3=B5=EC=97=86=EC=9D=B4=20=EA=B0=80=EC=A0=B8=EC=98=A4?= =?UTF-8?q?=EA=B8=B0=20=EA=B5=AC=ED=98=84=20#41?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../naechinso/domain/TestController.java | 147 +++++++++++++++++- .../naechinso/domain/card/CardController.java | 19 ++- .../naechinso/domain/card/CardRepository.java | 8 + .../naechinso/domain/card/CardService.java | 59 ++++++- .../naechinso/domain/card/entity/Card.java | 4 + .../domain/member/MemberRepository.java | 10 ++ .../domain/member/MemberService.java | 10 ++ .../domain/member/entity/Member.java | 6 + .../domain/recommend/RecommendService.java | 1 + .../naechinso/global/error/ErrorCode.java | 6 + 10 files changed, 258 insertions(+), 12 deletions(-) diff --git a/src/main/java/com/tikitaka/naechinso/domain/TestController.java b/src/main/java/com/tikitaka/naechinso/domain/TestController.java index 737d9d1..7b19bd3 100644 --- a/src/main/java/com/tikitaka/naechinso/domain/TestController.java +++ b/src/main/java/com/tikitaka/naechinso/domain/TestController.java @@ -1,5 +1,7 @@ package com.tikitaka.naechinso.domain; +import com.tikitaka.naechinso.domain.card.CardRepository; +import com.tikitaka.naechinso.domain.card.CardService; import com.tikitaka.naechinso.domain.member.MemberDetailRepository; import com.tikitaka.naechinso.domain.member.MemberRepository; import com.tikitaka.naechinso.domain.member.MemberService; @@ -21,6 +23,9 @@ import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collections; import java.util.List; /** @@ -33,13 +38,13 @@ @RequestMapping("/test") public class TestController { private final MemberService memberService; - private final MemberRepository memberRepository; - private final MemberDetailRepository memberDetailRepository; private final RecommendService recommendService; private final RecommendRepository recommendRepository; private final PendingService pendingService; + private final CardService cardService; + private final CardRepository cardRepository; @GetMapping("/request-member") @ApiOperation(value = "[*TEST*] 추천사를 요청하는 유저를 생성하고 엑세스 토큰을 반환한다") @@ -141,6 +146,22 @@ public CommonApiResponse createJobPendingMember( } + @GetMapping("/create-cards-each") + @ApiOperation(value = "[*TEST*] 생성한 두 유저의 카드를 각각 생성한다") + public CommonApiResponse createCardsEach( + ) { + Member member1 = memberService.findByPhone("01011111111"); + Member member2 = memberService.findByPhone("01012345678"); + + cardService.createCard(member1); + cardService.createCard(member1); + cardService.createCard(member2); + cardService.createCard(member2); + + return CommonApiResponse.of(true); + + } + @GetMapping("/create-job-pending-and-recommend-other") @ApiOperation(value = "[*TEST*] 직업 업데이트 요청하는 멤버를 생성하고 유저 한명을 추천한 뒤 다른 유저의 엑세스 토큰을 반환한다") @@ -320,4 +341,126 @@ public CommonApiResponse createTwoRegularMember() { return CommonApiResponse.of(senderDTO); } + + + + + @GetMapping("/create-multiple-users") + @ApiOperation(value = "[*TEST*] 멤버 DB를 초기화한 후, 정회원으로 가입한 유저를 남녀 10명씩 생성하고, 멤버 하나의 엑세스 토큰 반환") + public CommonApiResponse createMultipleMembers() { + + memberRepository.deleteAll(); + recommendRepository.deleteAll(); + + List adminMemberInfo = Arrays.asList("01012345678", 25, Gender.M, "노경닉", "edu-image-admin.jpg", "홍익", "대학교", "컴퓨터공학과"); //어드민 겸 추천인 + + + Member adminMember = memberService.findByPhone(memberService.joinCommonMember( + (String) adminMemberInfo.get(0), + MemberCommonJoinRequestDTO.builder() + .age((int) adminMemberInfo.get(1)) + .gender((Gender) adminMemberInfo.get(2)) + .name((String) adminMemberInfo.get(3)) + .acceptsInfo(true) + .acceptsLocation(true) + .acceptsMarketing(true) + .acceptsReligion(true) + .acceptsService(true) + .build()).getPhone()); + adminMember.updateEdu(MemberUpdateEduRequestDTO.builder() + .eduImage((String) adminMemberInfo.get(4)) + .eduName((String) adminMemberInfo.get(5)) + .eduLevel((String) adminMemberInfo.get(6)) + .eduMajor((String) adminMemberInfo.get(7)) + .build()); + adminMember.setAdmin(); + memberRepository.save(adminMember); + + final List> joinRequestList = Arrays.asList( + Arrays.asList("01011111111", 25, Gender.M, "허시준", "edu-image001.jpg", "서강", "대학교", "컴퓨터공학과", "1~3년", "CMC에서 만남", "착함", "자기관리, 귀여워, 차분해", "자기 일을 진짜 책임감 있게 잘하고 주변을 늘 먼저 생각하는 친구야", "서울시 마포구", "1병", 180, "내친소 사용하기", "profile-001-01.png,profile-001-02.png,profile-001-03.png", "반갑습니다 내친소 여러분!", "ESTJ", "열정적인, 상냥한, 섬세한", "무교", "비흡연자", "같이 취미를 즐길 수 있는 연애를 하고 싶어"), + Arrays.asList("01012222222", 26, Gender.M, "민성진", "edu-image002.jpg", "한국", "고등학교", "자동차정비", "1~3년", "CMC에서 만남", "착함", "자기관리, 귀여워, 차분해", "자기 일을 진짜 책임감 있게 잘하고 주변을 늘 먼저 생각하는 친구야", "서울시 마포구", "1병", 185, "내친소 사용하기", "profile-001-01.png,profile-001-02.png,profile-001-03.png", "반갑습니다 내친소 여러분!", "INFP", "열정적인, 상냥한, 섬세한", "무교", "비흡연자", "같이 취미를 즐길 수 있는 연애를 하고 싶어"), + Arrays.asList("01013333333", 27, Gender.M, "김상혁", "edu-image003.jpg", "서울", "대학원", "인공지능공학", "1~3년", "CMC에서 만남", "착함", "자기관리, 귀여워, 차분해", "자기 일을 진짜 책임감 있게 잘하고 주변을 늘 먼저 생각하는 친구야", "서울시 마포구", "1병", 182, "내친소 사용하기", "profile-001-01.png,profile-001-02.png,profile-001-03.png", "반갑습니다 내친소 여러분!", "ESTJ", "열정적인, 상냥한, 섬세한", "기독교", "비흡연자", "같이 취미를 즐길 수 있는 연애를 하고 싶어"), + Arrays.asList("01014444444", 28, Gender.M, "권영성", "edu-image004.jpg", "홍익", "대학교", "시각디자인학과", "1~3년", "CMC에서 만남", "착함", "자기관리, 귀여워, 차분해", "자기 일을 진짜 책임감 있게 잘하고 주변을 늘 먼저 생각하는 친구야", "서울시 마포구", "1병", 183, "내친소 사용하기", "profile-001-01.png,profile-001-02.png,profile-001-03.png", "반갑습니다 내친소 여러분!", "INFJ", "열정적인, 상냥한, 섬세한", "불교", "비흡연자", "같이 취미를 즐길 수 있는 연애를 하고 싶어"), + Arrays.asList("01015555555", 29, Gender.M, "배규빈", "edu-image005.jpg", "한성", "고등학교", "상업", "3~5년", "CMC에서 만남", "착함", "자기관리, 귀여워, 차분해", "자기 일을 진짜 책임감 있게 잘하고 주변을 늘 먼저 생각하는 친구야", "서울시 마포구", "1병", 178, "내친소 사용하기", "profile-001-01.png,profile-001-02.png,profile-001-03.png", "반갑습니다 내친소 여러분!", "ESTJ", "열정적인, 상냥한, 섬세한", "무교", "비흡연자", "같이 취미를 즐길 수 있는 연애를 하고 싶어"), + Arrays.asList("01016666666", 30, Gender.M, "권민기", "edu-image006.jpg", "서울", "고등학교", "디자인", "3~5년", "CMC에서 만남", "착함", "자기관리, 귀여워, 차분해", "자기 일을 진짜 책임감 있게 잘하고 주변을 늘 먼저 생각하는 친구야", "서울시 마포구", "1병", 172, "내친소 사용하기", "profile-001-01.png,profile-001-02.png,profile-001-03.png", "반갑습니다 내친소 여러분!", "ESFJ", "열정적인, 상냥한, 섬세한", "무교", "비흡연자", "같이 취미를 즐길 수 있는 연애를 하고 싶어"), + Arrays.asList("01017777777", 31, Gender.M, "김민성", "edu-image007.jpg", "연세", "대학원", "영어영문학과", "1~3년", "CMC에서 만남", "착함", "자기관리, 귀여워, 차분해", "자기 일을 진짜 책임감 있게 잘하고 주변을 늘 먼저 생각하는 친구야", "서울시 마포구", "1병", 173, "내친소 사용하기", "profile-001-01.png,profile-001-02.png,profile-001-03.png", "반갑습니다 내친소 여러분!", "ENFP", "열정적인, 상냥한, 섬세한", "기독교", "비흡연자", "같이 취미를 즐길 수 있는 연애를 하고 싶어"), + Arrays.asList("01018888888", 32, Gender.M, "임정혁", "edu-image008.jpg", "연세", "대학교", "전기전자공학과", "1~3년", "CMC에서 만남", "착함", "자기관리, 귀여워, 차분해", "자기 일을 진짜 책임감 있게 잘하고 주변을 늘 먼저 생각하는 친구야", "서울시 마포구", "1병", 175, "내친소 사용하기", "profile-001-01.png,profile-001-02.png,profile-001-03.png", "반갑습니다 내친소 여러분!", "ESTJ", "열정적인, 상냥한, 섬세한", "무교", "비흡연자", "같이 취미를 즐길 수 있는 연애를 하고 싶어"), + Arrays.asList("01019999999", 33, Gender.M, "성재오", "edu-image009.jpg", "이대부속", "고등학교", "공학", "1~3년", "CMC에서 만남", "착함", "자기관리, 귀여워, 차분해", "자기 일을 진짜 책임감 있게 잘하고 주변을 늘 먼저 생각하는 친구야", "서울시 마포구", "1병", 168, "내친소 사용하기", "profile-001-01.png,profile-001-02.png,profile-001-03.png", "반갑습니다 내친소 여러분!", "ESTJ", "열정적인, 상냥한, 섬세한", "무교", "비흡연자", "같이 취미를 즐길 수 있는 연애를 하고 싶어"), + Arrays.asList("01010000000", 25, Gender.M, "차재훈", "edu-image010.jpg", "국민", "대학교", "미디어학과", "1~3년", "CMC에서 만남", "착함", "자기관리, 귀여워, 차분해", "자기 일을 진짜 책임감 있게 잘하고 주변을 늘 먼저 생각하는 친구야", "서울시 마포구", "1병", 176, "내친소 사용하기", "profile-001-01.png,profile-001-02.png,profile-001-03.png", "반갑습니다 내친소 여러분!", "ESTP", "열정적인, 상냥한, 섬세한", "무교", "비흡연자", "같이 취미를 즐길 수 있는 연애를 하고 싶어"), + + Arrays.asList("01022200000", 25, Gender.W, "민장효", "edu-image011.jpg", "서강", "대학원", "물류학과", "1~3년", "CMC에서 만남", "착함", "자기관리, 귀여워, 차분해", "자기 일을 진짜 책임감 있게 잘하고 주변을 늘 먼저 생각하는 친구야", "서울시 마포구", "1병", 160, "내친소 사용하기", "profile-001-01.png,profile-001-02.png,profile-001-03.png", "반갑습니다 내친소 여러분!", "INFP", "열정적인, 상냥한, 섬세한", "무교", "비흡연자", "같이 취미를 즐길 수 있는 연애를 하고 싶어"), + Arrays.asList("01022211111", 25, Gender.W, "김민서", "edu-image012.jpg", "홍익", "대학교", "조소과", "1~3년", "CMC에서 만남", "착함", "자기관리, 귀여워, 차분해", "자기 일을 진짜 책임감 있게 잘하고 주변을 늘 먼저 생각하는 친구야", "서울시 마포구", "1병", 162, "내친소 사용하기", "profile-001-01.png,profile-001-02.png,profile-001-03.png", "반갑습니다 내친소 여러분!", "ESTJ", "열정적인, 상냥한, 섬세한", "무교", "비흡연자", "같이 취미를 즐길 수 있는 연애를 하고 싶어"), + Arrays.asList("01022222222", 25, Gender.W, "노혜지", "edu-image013.jpg", "한국", "고등학교", "디자인", "1~3년", "CMC에서 만남", "착함", "자기관리, 귀여워, 차분해", "자기 일을 진짜 책임감 있게 잘하고 주변을 늘 먼저 생각하는 친구야", "서울시 마포구", "1병", 165, "내친소 사용하기", "profile-001-01.png,profile-001-02.png,profile-001-03.png", "반갑습니다 내친소 여러분!", "ENFP", "열정적인, 상냥한, 섬세한", "기독교", "비흡연자", "같이 취미를 즐길 수 있는 연애를 하고 싶어"), + Arrays.asList("01022233333", 25, Gender.W, "류라해", "edu-image014.jpg", "이화여자", "대학교", "사이버보안학과", "1~3년", "CMC에서 만남", "착함", "자기관리, 귀여워, 차분해", "자기 일을 진짜 책임감 있게 잘하고 주변을 늘 먼저 생각하는 친구야", "서울시 마포구", "1병", 155, "내친소 사용하기", "profile-001-01.png,profile-001-02.png,profile-001-03.png", "반갑습니다 내친소 여러분!", "ESTJ", "열정적인, 상냥한, 섬세한", "기독교", "비흡연자", "같이 취미를 즐길 수 있는 연애를 하고 싶어"), + Arrays.asList("01022244444", 25, Gender.W, "민예지", "edu-image015.jpg", "이화여자", "대학교", "국어국문학과", "3~5년", "CMC에서 만남", "착함", "자기관리, 귀여워, 차분해", "자기 일을 진짜 책임감 있게 잘하고 주변을 늘 먼저 생각하는 친구야", "서울시 마포구", "1병", 150, "내친소 사용하기", "profile-001-01.png,profile-001-02.png,profile-001-03.png", "반갑습니다 내친소 여러분!", "INFJ", "열정적인, 상냥한, 섬세한", "무교", "비흡연자", "같이 취미를 즐길 수 있는 연애를 하고 싶어"), + Arrays.asList("01022255555", 25, Gender.W, "류유주", "edu-image016.jpg", "한국", "고등학교", "공학", "1~3년", "CMC에서 만남", "착함", "자기관리, 귀여워, 차분해", "자기 일을 진짜 책임감 있게 잘하고 주변을 늘 먼저 생각하는 친구야", "서울시 마포구", "1병", 174, "내친소 사용하기", "profile-001-01.png,profile-001-02.png,profile-001-03.png", "반갑습니다 내친소 여러분!", "INTP", "열정적인, 상냥한, 섬세한", "기독교", "비흡연자", "같이 취미를 즐길 수 있는 연애를 하고 싶어"), + Arrays.asList("01022266666", 25, Gender.W, "임혜서", "edu-image017.jpg", "서울", "대학원", "법학과", "1~3년", "CMC에서 만남", "착함", "자기관리, 귀여워, 차분해", "자기 일을 진짜 책임감 있게 잘하고 주변을 늘 먼저 생각하는 친구야", "서울시 마포구", "1병", 172, "내친소 사용하기", "profile-001-01.png,profile-001-02.png,profile-001-03.png", "반갑습니다 내친소 여러분!", "ESTJ", "열정적인, 상냥한, 섬세한", "불교", "비흡연자", "같이 취미를 즐길 수 있는 연애를 하고 싶어"), + Arrays.asList("01022277777", 25, Gender.W, "임한하", "edu-image018.jpg", "서울", "대학교", "의상학과", "3~5년", "CMC에서 만남", "착함", "자기관리, 귀여워, 차분해", "자기 일을 진짜 책임감 있게 잘하고 주변을 늘 먼저 생각하는 친구야", "서울시 마포구", "1병", 168, "내친소 사용하기", "profile-001-01.png,profile-001-02.png,profile-001-03.png", "반갑습니다 내친소 여러분!", "ENTP", "열정적인, 상냥한, 섬세한", "무교", "비흡연자", "같이 취미를 즐길 수 있는 연애를 하고 싶어"), + Arrays.asList("01022288888", 25, Gender.W, "권민영", "edu-image019.jpg", "고려", "대학교", "의학", "1~3년", "CMC에서 만남", "착함", "자기관리, 귀여워, 차분해", "자기 일을 진짜 책임감 있게 잘하고 주변을 늘 먼저 생각하는 친구야", "서울시 마포구", "1병", 175, "내친소 사용하기", "profile-001-01.png,profile-001-02.png,profile-001-03.png", "반갑습니다 내친소 여러분!", "ESFJ", "열정적인, 상냥한, 섬세한", "무교", "비흡연자", "같이 취미를 즐길 수 있는 연애를 하고 싶어"), + Arrays.asList("01022299999", 25, Gender.W, "진하수", "edu-image020.jpg", "연세", "대학교", "기계공학과", "1~3년", "CMC에서 만남", "착함", "자기관리, 귀여워, 차분해", "자기 일을 진짜 책임감 있게 잘하고 주변을 늘 먼저 생각하는 친구야", "서울시 마포구", "1병", 163, "내친소 사용하기", "profile-001-01.png,profile-001-02.png,profile-001-03.png", "반갑습니다 내친소 여러분!", "ESTJ", "열정적인, 상냥한, 섬세한", "무교", "비흡연자", "같이 취미를 즐길 수 있는 연애를 하고 싶어") + ); + + joinRequestList.forEach(info -> { + MemberCommonJoinResponseDTO senderDTO = memberService.joinCommonMember( + (String) info.get(0), + MemberCommonJoinRequestDTO.builder() + .age((int) info.get(1)) + .gender((Gender) info.get(2)) + .name((String) info.get(3)) + .acceptsInfo(true) + .acceptsLocation(true) + .acceptsMarketing(true) + .acceptsReligion(true) + .acceptsService(true) + .build()); + + Member member = memberService.findByPhone(senderDTO.getPhone()); + + member.updateEdu(MemberUpdateEduRequestDTO.builder() + .eduImage((String) info.get(4)) + .eduName((String) info.get(5)) + .eduLevel((String) info.get(6)) + .eduMajor((String) info.get(7)) + .build()); + + memberRepository.save(member); + memberRepository.flush(); + + recommendService.createRecommend(adminMember, RecommendBySenderRequestDTO + .builder() + .phone((String) info.get(0)) + .age((int) info.get(1)) + .gender((Gender) info.get(2)) + .name((String) info.get(3)) + .period((String) info.get(8)) + .meet((String) info.get(9)) + .personality((String) info.get(10)) + .appeal((String) info.get(11)) + .appealDetail((String) info.get(12)) + .build()); + + + memberDetailRepository.save( + MemberDetail.builder() + .member(member) + .address((String) info.get(13)) + .drink((String) info.get(14)) + .height((int) info.get(15)) + .hobby((String) info.get(16)) + .images((String) info.get(17)) + .image_accepted(true) + .introduce((String) info.get(18)) + .mbti((String) info.get(19)) + .personality((String) info.get(20)) + .religion((String) info.get(21)) + .smoke((String) info.get(22)) + .style((String) info.get(23)) + .build() + ); + + + System.out.println(senderDTO.getAccessToken()); + }); + return CommonApiResponse.of(true); + } } diff --git a/src/main/java/com/tikitaka/naechinso/domain/card/CardController.java b/src/main/java/com/tikitaka/naechinso/domain/card/CardController.java index d4166ff..2753b00 100644 --- a/src/main/java/com/tikitaka/naechinso/domain/card/CardController.java +++ b/src/main/java/com/tikitaka/naechinso/domain/card/CardController.java @@ -9,10 +9,7 @@ import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; import org.springframework.stereotype.Controller; -import org.springframework.web.bind.annotation.GetMapping; -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 springfox.documentation.annotations.ApiIgnore; @Slf4j @@ -27,7 +24,7 @@ public class CardController { public CommonApiResponse getAllCardsByMember( @ApiIgnore @AuthMember Member member ) { - return CommonApiResponse.of(cardService.findAllByMember(member)); + return CommonApiResponse.of(cardService.findAllDTOByMember(member)); } @GetMapping("/find") @@ -35,7 +32,7 @@ public CommonApiResponse getAllCardsByMember( public CommonApiResponse getAllCards( @ApiIgnore @AuthMember Member member ) { - return CommonApiResponse.of(cardService.findAll()); + return CommonApiResponse.of(cardService.findAllDTO()); } @@ -44,6 +41,14 @@ public CommonApiResponse getAllCards( public CommonApiResponse createCardByMember( @ApiIgnore @AuthMember Member member ) { - return CommonApiResponse.of(cardService.createCard(member)); + return CommonApiResponse.of(cardService.createRandomCard(member)); + } + + @PatchMapping + @ApiOperation(value = "현재 활성화된 카드를 거절한다 (AccessToken)") + public CommonApiResponse rejectCardByMember( + @ApiIgnore @AuthMember Member member + ) { + return CommonApiResponse.of(cardService.rejectCard(member)); } } diff --git a/src/main/java/com/tikitaka/naechinso/domain/card/CardRepository.java b/src/main/java/com/tikitaka/naechinso/domain/card/CardRepository.java index b2f0dc9..794289d 100644 --- a/src/main/java/com/tikitaka/naechinso/domain/card/CardRepository.java +++ b/src/main/java/com/tikitaka/naechinso/domain/card/CardRepository.java @@ -9,6 +9,7 @@ import java.time.LocalDateTime; import java.util.List; +import java.util.Optional; @Repository public interface CardRepository extends JpaRepository { @@ -16,6 +17,13 @@ public interface CardRepository extends JpaRepository { List findAllByMember(Member member); + Optional findByMemberAndIsActiveTrue(Member member); + Boolean existsByMemberAndIsActiveTrue(Member member); + @Query("select c.targetId " + + "from Card c " + + "where c.targetId <> :id") + List findTargetIdsByIdNot(Long id); + @Query("select new com.tikitaka.naechinso.domain.card.dto.CardResponseDTO(c.targetId, c.isActive, c.createdAt) " + "from Card c " + "join c.member m " + diff --git a/src/main/java/com/tikitaka/naechinso/domain/card/CardService.java b/src/main/java/com/tikitaka/naechinso/domain/card/CardService.java index c3aea82..d72c4a8 100644 --- a/src/main/java/com/tikitaka/naechinso/domain/card/CardService.java +++ b/src/main/java/com/tikitaka/naechinso/domain/card/CardService.java @@ -3,13 +3,20 @@ import com.tikitaka.naechinso.domain.card.dto.CardResponseDTO; import com.tikitaka.naechinso.domain.card.entity.Card; import com.tikitaka.naechinso.domain.member.MemberService; +import com.tikitaka.naechinso.domain.member.constant.Gender; import com.tikitaka.naechinso.domain.member.entity.Member; +import com.tikitaka.naechinso.global.error.ErrorCode; +import com.tikitaka.naechinso.global.error.exception.BadRequestException; +import com.tikitaka.naechinso.global.error.exception.NotFoundException; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; +import java.util.Arrays; +import java.util.Collection; import java.util.List; +import java.util.stream.Collectors; @Slf4j @Service @@ -33,13 +40,59 @@ public CardResponseDTO createCard(Member authMember) { return CardResponseDTO.of(newCard); } - public List findAllByMember(Member member) { + /** + * 추천 받았던 유저를 필터링한 랜덤 추천 카드를 만든다 + * */ + public CardResponseDTO createRandomCard(Member authMember) { + //아직 ACTIVE 한 카드가 있으면 에러 + if (cardRepository.existsByMemberAndIsActiveTrue(authMember)) { + throw new BadRequestException(ErrorCode.ACTIVE_CARD_ALREADY_EXIST); + } + + Member member = memberService.findByMember(authMember); + Gender memberGender = member.getGender(); + + //이미 존재하는 카드에 담긴 유저 ID들 + List existTargetMemberIds = member.getCards().stream().map(Card::getTargetId).collect(Collectors.toList()); + existTargetMemberIds.add(member.getId()); + + //새로운 추천 상대 + Member newTargetMember = memberService.findTopByIdNotInAndGenderNot(existTargetMemberIds, memberGender); + + Card newCard = Card.builder() + .member(member) + .targetId(newTargetMember.getId()) + .isActive(true) + .build(); + + cardRepository.save(newCard); + + return CardResponseDTO.of(newCard); + } + + + /** + * 현재 ACTIVE 한 카드를 거절하여 INACTIVE 상태로 만든다 + * */ + public CardResponseDTO rejectCard(Member authMember) { + Card activeCard = findByMemberAndIsActiveTrue(authMember); + activeCard.disable(); + + cardRepository.save(activeCard); + + return CardResponseDTO.of(activeCard); + } + + public List findAllDTOByMember(Member member) { return cardRepository.findAllDTOByMember(member); } - public List findAll() { + public List findAllDTO() { return cardRepository.findAllDTO(); } - + public Card findByMemberAndIsActiveTrue(Member member) { + return cardRepository.findByMemberAndIsActiveTrue(member) + .orElseThrow(() -> new NotFoundException(ErrorCode.ACTIVE_CARD_NOT_FOUND)); + } } diff --git a/src/main/java/com/tikitaka/naechinso/domain/card/entity/Card.java b/src/main/java/com/tikitaka/naechinso/domain/card/entity/Card.java index 1b551e1..f7eafc0 100644 --- a/src/main/java/com/tikitaka/naechinso/domain/card/entity/Card.java +++ b/src/main/java/com/tikitaka/naechinso/domain/card/entity/Card.java @@ -36,4 +36,8 @@ public class Card extends BaseEntity { @Column(name = "car_is_active") @Builder.Default private Boolean isActive = false; + + public void disable() { + this.isActive = false; + } } diff --git a/src/main/java/com/tikitaka/naechinso/domain/member/MemberRepository.java b/src/main/java/com/tikitaka/naechinso/domain/member/MemberRepository.java index 9246e5f..0999b04 100644 --- a/src/main/java/com/tikitaka/naechinso/domain/member/MemberRepository.java +++ b/src/main/java/com/tikitaka/naechinso/domain/member/MemberRepository.java @@ -1,10 +1,15 @@ package com.tikitaka.naechinso.domain.member; +import com.tikitaka.naechinso.domain.member.constant.Gender; import com.tikitaka.naechinso.domain.member.entity.Member; import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.data.jpa.repository.Query; +import org.springframework.data.repository.query.Param; import org.springframework.stereotype.Repository; import javax.swing.text.html.Option; +import java.util.Collection; +import java.util.List; import java.util.Optional; @Repository @@ -12,4 +17,9 @@ public interface MemberRepository extends JpaRepository { Optional findByPhone(String phone); + Optional findTopByIdNotInAndGenderNot(Collection ids, Gender gender); + + + Optional findTopByGenderNot(Gender gender); + } diff --git a/src/main/java/com/tikitaka/naechinso/domain/member/MemberService.java b/src/main/java/com/tikitaka/naechinso/domain/member/MemberService.java index cd37599..5667be1 100644 --- a/src/main/java/com/tikitaka/naechinso/domain/member/MemberService.java +++ b/src/main/java/com/tikitaka/naechinso/domain/member/MemberService.java @@ -1,5 +1,6 @@ package com.tikitaka.naechinso.domain.member; +import com.tikitaka.naechinso.domain.member.constant.Gender; import com.tikitaka.naechinso.domain.member.dto.*; import com.tikitaka.naechinso.domain.member.entity.Member; import com.tikitaka.naechinso.domain.member.entity.MemberDetail; @@ -20,6 +21,8 @@ import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; +import java.util.Arrays; +import java.util.Collection; import java.util.List; import java.util.Optional; import java.util.stream.Collectors; @@ -181,6 +184,13 @@ public Member findById(Long memberId) { .orElseThrow(() -> new NotFoundException(ErrorCode.USER_NOT_FOUND)); } + /** 이미 추천받은 카드들에 있는 유저 ID 에 해당하지 않으며 + * 매개변수 성별과 값이 다른 유저 한명을 가져온다 */ + public Member findTopByIdNotInAndGenderNot(Collection ids, Gender gender) { + return memberRepository.findTopByIdNotInAndGenderNot(ids, gender) + .orElseThrow(() -> new NotFoundException(ErrorCode.RANDOM_USER_NOT_FOUND)); + } + public boolean existsById(Long memberId) { return memberRepository.existsById(memberId); } diff --git a/src/main/java/com/tikitaka/naechinso/domain/member/entity/Member.java b/src/main/java/com/tikitaka/naechinso/domain/member/entity/Member.java index 7eb9875..5cb8ad4 100644 --- a/src/main/java/com/tikitaka/naechinso/domain/member/entity/Member.java +++ b/src/main/java/com/tikitaka/naechinso/domain/member/entity/Member.java @@ -120,6 +120,7 @@ public class Member extends BaseEntity { //내 가입 대기 정보 @OneToMany(mappedBy = "member") + @ToString.Exclude @JsonIgnore private List pending = new ArrayList<>(); @@ -130,12 +131,14 @@ public class Member extends BaseEntity { //내가 보낸 호감 내역 @OneToMany(mappedBy = "fromMember") + @ToString.Exclude @JsonIgnore @Builder.Default private List matchesTo = new ArrayList<>(); //내가 받은 호감 내역 @OneToMany(mappedBy = "toMember") + @ToString.Exclude @JsonIgnore @Builder.Default private List matchesFrom = new ArrayList<>(); @@ -143,15 +146,18 @@ public class Member extends BaseEntity { //내가 소개해준 사람들 //mapped by 에는 연관관계 엔티티의 필드명을 적어줌 @OneToMany(mappedBy = "sender") + @ToString.Exclude @JsonIgnore private List recommends = new ArrayList<>(); //나를 소개해준 사람들 @OneToMany(mappedBy = "receiver") + @ToString.Exclude @JsonIgnore //순환참조 방지, 엔티티 프로퍼티 가려줌 private List recommendReceived = new ArrayList<>(); @OneToMany(mappedBy = "member", cascade = CascadeType.ALL) + @ToString.Exclude @JsonIgnore private List cards; diff --git a/src/main/java/com/tikitaka/naechinso/domain/recommend/RecommendService.java b/src/main/java/com/tikitaka/naechinso/domain/recommend/RecommendService.java index a47e430..e38840c 100644 --- a/src/main/java/com/tikitaka/naechinso/domain/recommend/RecommendService.java +++ b/src/main/java/com/tikitaka/naechinso/domain/recommend/RecommendService.java @@ -83,6 +83,7 @@ public RecommendResponseDTO createRecommend(Member authMember, RecommendBySender .receiverAge(dto.getAge()) .receiverGender(dto.getGender()) .receiverAppeal(dto.getAppeal()) + .receiverAppealDetail(dto.getAppealDetail()) .receiverMeet(dto.getMeet()) .receiverPersonality(dto.getPersonality()) .receiverPeriod(dto.getPeriod()) diff --git a/src/main/java/com/tikitaka/naechinso/global/error/ErrorCode.java b/src/main/java/com/tikitaka/naechinso/global/error/ErrorCode.java index cb39f8d..4e32253 100644 --- a/src/main/java/com/tikitaka/naechinso/global/error/ErrorCode.java +++ b/src/main/java/com/tikitaka/naechinso/global/error/ErrorCode.java @@ -49,6 +49,7 @@ public enum ErrorCode { USER_NOT_FOUND(NOT_FOUND, "U003","해당 유저 정보를 찾을 수 없습니다"), NOT_FOLLOW(NOT_FOUND, "U004","팔로우 중이지 않습니다"), DUPLICATE_PENDING_REQUEST(BAD_REQUEST, "U005","동일한 종류의 심사 요청은 한 번만 보낼 수 있습니다"), + RANDOM_USER_NOT_FOUND(NOT_FOUND, "U006","추천할 수 있는 유저가 더 이상 없습니다"), /* Recommend 관련 오류 */ @@ -77,6 +78,11 @@ public enum ErrorCode { PENDING_ALREADY_PROCESSED(BAD_REQUEST, "PEND001", "이미 처리 완료된 요청입니다"), + /* 카드 관련 */ + ACTIVE_CARD_NOT_FOUND(NOT_FOUND, "CARD000", "유효한 추천 카드를 찾을 수 없습니다"), + ACTIVE_CARD_ALREADY_EXIST(BAD_REQUEST, "CARD001", "추천 카드는 한 장씩만 받을 수 있습니다"), + + ; private final HttpStatus httpStatus; From f306ee0bcd025e1b9104d233797c563e7533a209 Mon Sep 17 00:00:00 2001 From: gengminy Date: Tue, 18 Oct 2022 16:03:12 +0900 Subject: [PATCH 30/72] =?UTF-8?q?:rocket:=20feat(card):=20=EC=B9=B4?= =?UTF-8?q?=EB=93=9C=20=EC=83=81=EB=8C=80=EB=B0=A9=20=EC=9C=A0=EC=A0=80=20?= =?UTF-8?q?=ED=94=84=EB=A1=9C=ED=95=84=20=EA=B0=80=EC=A0=B8=EC=98=A4?= =?UTF-8?q?=EB=8A=94=20=EB=A1=9C=EC=A7=81=20=EC=B6=94=EA=B0=80=20#41?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../naechinso/domain/card/CardService.java | 14 +++++++++----- .../domain/member/MemberController.java | 2 +- .../domain/member/MemberRepository.java | 3 +++ .../naechinso/domain/member/MemberService.java | 16 +++++++++++++--- .../naechinso/global/error/ErrorCode.java | 1 + 5 files changed, 27 insertions(+), 9 deletions(-) diff --git a/src/main/java/com/tikitaka/naechinso/domain/card/CardService.java b/src/main/java/com/tikitaka/naechinso/domain/card/CardService.java index d72c4a8..eddbd3c 100644 --- a/src/main/java/com/tikitaka/naechinso/domain/card/CardService.java +++ b/src/main/java/com/tikitaka/naechinso/domain/card/CardService.java @@ -2,6 +2,7 @@ import com.tikitaka.naechinso.domain.card.dto.CardResponseDTO; import com.tikitaka.naechinso.domain.card.entity.Card; +import com.tikitaka.naechinso.domain.member.MemberRepository; import com.tikitaka.naechinso.domain.member.MemberService; import com.tikitaka.naechinso.domain.member.constant.Gender; import com.tikitaka.naechinso.domain.member.entity.Member; @@ -24,11 +25,12 @@ public class CardService { private final CardRepository cardRepository; - private final MemberService memberService; + private final MemberRepository memberRepository; public CardResponseDTO createCard(Member authMember) { - Member member = memberService.findByMember(authMember); + Member member = memberRepository.findByMember(authMember) + .orElseThrow(() -> new NotFoundException(ErrorCode.USER_NOT_FOUND)); Card newCard = Card.builder() .member(member) @@ -49,7 +51,8 @@ public CardResponseDTO createRandomCard(Member authMember) { throw new BadRequestException(ErrorCode.ACTIVE_CARD_ALREADY_EXIST); } - Member member = memberService.findByMember(authMember); + Member member = memberRepository.findByMember(authMember) + .orElseThrow(() -> new NotFoundException(ErrorCode.USER_NOT_FOUND)); Gender memberGender = member.getGender(); //이미 존재하는 카드에 담긴 유저 ID들 @@ -57,7 +60,8 @@ public CardResponseDTO createRandomCard(Member authMember) { existTargetMemberIds.add(member.getId()); //새로운 추천 상대 - Member newTargetMember = memberService.findTopByIdNotInAndGenderNot(existTargetMemberIds, memberGender); + Member newTargetMember = memberRepository.findTopByIdNotInAndGenderNot(existTargetMemberIds, memberGender) + .orElseThrow(() -> new NotFoundException(ErrorCode.RANDOM_USER_NOT_FOUND)); Card newCard = Card.builder() .member(member) @@ -72,7 +76,7 @@ public CardResponseDTO createRandomCard(Member authMember) { /** - * 현재 ACTIVE 한 카드를 거절하여 INACTIVE 상태로 만든다 + * 현재 ACTIVE 한 카드를 모두 거절하고 INACTIVE 상태로 만든다 * */ public CardResponseDTO rejectCard(Member authMember) { Card activeCard = findByMemberAndIsActiveTrue(authMember); diff --git a/src/main/java/com/tikitaka/naechinso/domain/member/MemberController.java b/src/main/java/com/tikitaka/naechinso/domain/member/MemberController.java index a2b4800..5840a44 100644 --- a/src/main/java/com/tikitaka/naechinso/domain/member/MemberController.java +++ b/src/main/java/com/tikitaka/naechinso/domain/member/MemberController.java @@ -50,7 +50,7 @@ public CommonApiResponse getMemberProfileById( @PathVariable("id") Long id, @ApiIgnore @AuthMember Member member ) { - return CommonApiResponse.of(memberService.readOppositeMemberDetailAndRecommendById(id)); + return CommonApiResponse.of(memberService.readOppositeMemberDetailAndRecommendById(member, id)); } @GetMapping("/detail") diff --git a/src/main/java/com/tikitaka/naechinso/domain/member/MemberRepository.java b/src/main/java/com/tikitaka/naechinso/domain/member/MemberRepository.java index 0999b04..e40c848 100644 --- a/src/main/java/com/tikitaka/naechinso/domain/member/MemberRepository.java +++ b/src/main/java/com/tikitaka/naechinso/domain/member/MemberRepository.java @@ -19,6 +19,9 @@ public interface MemberRepository extends JpaRepository { Optional findTopByIdNotInAndGenderNot(Collection ids, Gender gender); + @Query("SELECT m FROM Member m WHERE m = :member") + Optional findByMember(Member member); + Optional findTopByGenderNot(Gender gender); diff --git a/src/main/java/com/tikitaka/naechinso/domain/member/MemberService.java b/src/main/java/com/tikitaka/naechinso/domain/member/MemberService.java index 5667be1..fbca9a5 100644 --- a/src/main/java/com/tikitaka/naechinso/domain/member/MemberService.java +++ b/src/main/java/com/tikitaka/naechinso/domain/member/MemberService.java @@ -1,5 +1,7 @@ package com.tikitaka.naechinso.domain.member; +import com.tikitaka.naechinso.domain.card.CardService; +import com.tikitaka.naechinso.domain.card.entity.Card; import com.tikitaka.naechinso.domain.member.constant.Gender; import com.tikitaka.naechinso.domain.member.dto.*; import com.tikitaka.naechinso.domain.member.entity.Member; @@ -34,6 +36,7 @@ public class MemberService { private final JwtTokenProvider jwtTokenProvider; private final PendingService pendingService; + private final CardService cardService; private final MemberRepository memberRepository; private final MemberDetailRepository memberDetailRepository; @@ -94,10 +97,17 @@ public MemberDetailResponseDTO readDetail(Member member) { /** * 랜덤 추천받은 상대의 프로필 카드를 가져오는 서비스 로직 - * @// TODO: 2022/10/13 서로 연관 있는 상태가 아닐때 접근할 수 없도록 해야함 + * ACTIVE 한 카드에만 접근 권한이 있음 * */ - public MemberOppositeProfileResponseDTO readOppositeMemberDetailAndRecommendById(Long id) { - Member oppositeMember = findById(id); + public MemberOppositeProfileResponseDTO readOppositeMemberDetailAndRecommendById(Member authMember, Long id) { + //현재 ACTIVE 한 카드와 요청 id가 같지 않으면 에러 + Card activeCard = cardService.findByMemberAndIsActiveTrue(authMember); + Long targetId = activeCard.getTargetId(); + if (!targetId.equals(id)) { + throw new ForbiddenException(ErrorCode.FORBIDDEN_PROFILE); + } + + Member oppositeMember = findById(targetId); return MemberOppositeProfileResponseDTO.of(oppositeMember); } diff --git a/src/main/java/com/tikitaka/naechinso/global/error/ErrorCode.java b/src/main/java/com/tikitaka/naechinso/global/error/ErrorCode.java index 4e32253..88e546c 100644 --- a/src/main/java/com/tikitaka/naechinso/global/error/ErrorCode.java +++ b/src/main/java/com/tikitaka/naechinso/global/error/ErrorCode.java @@ -50,6 +50,7 @@ public enum ErrorCode { NOT_FOLLOW(NOT_FOUND, "U004","팔로우 중이지 않습니다"), DUPLICATE_PENDING_REQUEST(BAD_REQUEST, "U005","동일한 종류의 심사 요청은 한 번만 보낼 수 있습니다"), RANDOM_USER_NOT_FOUND(NOT_FOUND, "U006","추천할 수 있는 유저가 더 이상 없습니다"), + FORBIDDEN_PROFILE(NOT_FOUND, "U007","해당 유저 프로필에 대한 접근 권한이 없습니다"), /* Recommend 관련 오류 */ From a07f111b2d70b0ce93cc49b3b0e61436ea1e8f33 Mon Sep 17 00:00:00 2001 From: gengminy Date: Tue, 18 Oct 2022 16:49:40 +0900 Subject: [PATCH 31/72] =?UTF-8?q?:hammer:=20fix(card):=20=EC=B9=B4?= =?UTF-8?q?=EB=93=9C=20=EC=8D=B8=EB=84=A4=EC=9D=BC=20=EC=A0=95=EB=B3=B4=20?= =?UTF-8?q?=ED=8F=AC=ED=95=A8=ED=95=98=EB=8F=84=EB=A1=9D=20=EC=88=98?= =?UTF-8?q?=EC=A0=95=20#41?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../naechinso/domain/TestController.java | 33 +++++++------- .../naechinso/domain/card/CardService.java | 31 ++++++------- .../domain/card/dto/CardResponseDTO.java | 45 +++++++++++++++++++ .../naechinso/domain/card/entity/Card.java | 5 +++ .../domain/member/MemberRepository.java | 2 +- .../domain/member/MemberService.java | 4 +- .../dto/MemberOppositeProfileResponseDTO.java | 7 ++- .../naechinso/global/error/ErrorCode.java | 1 + 8 files changed, 92 insertions(+), 36 deletions(-) diff --git a/src/main/java/com/tikitaka/naechinso/domain/TestController.java b/src/main/java/com/tikitaka/naechinso/domain/TestController.java index 7b19bd3..287e944 100644 --- a/src/main/java/com/tikitaka/naechinso/domain/TestController.java +++ b/src/main/java/com/tikitaka/naechinso/domain/TestController.java @@ -146,21 +146,21 @@ public CommonApiResponse createJobPendingMember( } - @GetMapping("/create-cards-each") - @ApiOperation(value = "[*TEST*] 생성한 두 유저의 카드를 각각 생성한다") - public CommonApiResponse createCardsEach( - ) { - Member member1 = memberService.findByPhone("01011111111"); - Member member2 = memberService.findByPhone("01012345678"); - - cardService.createCard(member1); - cardService.createCard(member1); - cardService.createCard(member2); - cardService.createCard(member2); - - return CommonApiResponse.of(true); - - } +// @GetMapping("/create-cards-each") +// @ApiOperation(value = "[*TEST*] 생성한 두 유저의 카드를 각각 생성한다") +// public CommonApiResponse createCardsEach( +// ) { +// Member member1 = memberService.findByPhone("01011111111"); +// Member member2 = memberService.findByPhone("01012345678"); +// +// cardService.createCard(member1); +// cardService.createCard(member1); +// cardService.createCard(member2); +// cardService.createCard(member2); +// +// return CommonApiResponse.of(true); +// +// } @GetMapping("/create-job-pending-and-recommend-other") @@ -352,8 +352,7 @@ public CommonApiResponse createMultipleMembers() { memberRepository.deleteAll(); recommendRepository.deleteAll(); - List adminMemberInfo = Arrays.asList("01012345678", 25, Gender.M, "노경닉", "edu-image-admin.jpg", "홍익", "대학교", "컴퓨터공학과"); //어드민 겸 추천인 - + List adminMemberInfo = Arrays.asList("01012345678", 25, Gender.M, "노경닉", "edu-image-admin.jpg", "홍익", "대학교", "컴퓨터공학과", "1~3년", "CMC에서 만남", "착함", "자기관리, 귀여워, 차분해", "자기 일을 진짜 책임감 있게 잘하고 주변을 늘 먼저 생각하는 친구야", "서울시 마포구", "1병", 180, "내친소 사용하기", "profile-001-01.png,profile-001-02.png,profile-001-03.png", "반갑습니다 내친소 여러분!", "ESTJ", "열정적인, 상냥한, 섬세한", "무교", "비흡연자", "같이 취미를 즐길 수 있는 연애를 하고 싶어"); //어드민 겸 추천인 Member adminMember = memberService.findByPhone(memberService.joinCommonMember( (String) adminMemberInfo.get(0), diff --git a/src/main/java/com/tikitaka/naechinso/domain/card/CardService.java b/src/main/java/com/tikitaka/naechinso/domain/card/CardService.java index eddbd3c..e91773e 100644 --- a/src/main/java/com/tikitaka/naechinso/domain/card/CardService.java +++ b/src/main/java/com/tikitaka/naechinso/domain/card/CardService.java @@ -27,20 +27,20 @@ public class CardService { private final CardRepository cardRepository; private final MemberRepository memberRepository; - public CardResponseDTO createCard(Member authMember) { - - Member member = memberRepository.findByMember(authMember) - .orElseThrow(() -> new NotFoundException(ErrorCode.USER_NOT_FOUND)); - - Card newCard = Card.builder() - .member(member) - .targetId(3L) - .build(); - - cardRepository.save(newCard); - - return CardResponseDTO.of(newCard); - } +// public CardResponseDTO createCard(Member authMember) { +// +// Member member = memberRepository.findByMember(authMember) +// .orElseThrow(() -> new NotFoundException(ErrorCode.USER_NOT_FOUND)); +// +// Card newCard = Card.builder() +// .member(member) +// .targetId(3L) +// .build(); +// +// cardRepository.save(newCard); +// +// return CardResponseDTO.of(newCard); +// } /** * 추천 받았던 유저를 필터링한 랜덤 추천 카드를 만든다 @@ -60,11 +60,12 @@ public CardResponseDTO createRandomCard(Member authMember) { existTargetMemberIds.add(member.getId()); //새로운 추천 상대 - Member newTargetMember = memberRepository.findTopByIdNotInAndGenderNot(existTargetMemberIds, memberGender) + Member newTargetMember = memberRepository.findTopByIdNotInAndGenderNotAndDetailNotNull(existTargetMemberIds, memberGender) .orElseThrow(() -> new NotFoundException(ErrorCode.RANDOM_USER_NOT_FOUND)); Card newCard = Card.builder() .member(member) + .target(newTargetMember) .targetId(newTargetMember.getId()) .isActive(true) .build(); diff --git a/src/main/java/com/tikitaka/naechinso/domain/card/dto/CardResponseDTO.java b/src/main/java/com/tikitaka/naechinso/domain/card/dto/CardResponseDTO.java index 2996bc0..115e637 100644 --- a/src/main/java/com/tikitaka/naechinso/domain/card/dto/CardResponseDTO.java +++ b/src/main/java/com/tikitaka/naechinso/domain/card/dto/CardResponseDTO.java @@ -2,9 +2,17 @@ import com.tikitaka.naechinso.domain.card.entity.Card; import com.tikitaka.naechinso.domain.match.constant.MatchStatus; +import com.tikitaka.naechinso.domain.member.constant.Gender; +import com.tikitaka.naechinso.domain.member.dto.MemberOppositeProfileResponseDTO; +import com.tikitaka.naechinso.domain.member.entity.Member; +import com.tikitaka.naechinso.domain.member.entity.MemberDetail; +import com.tikitaka.naechinso.global.error.ErrorCode; +import com.tikitaka.naechinso.global.error.exception.BadRequestException; +import com.tikitaka.naechinso.global.error.exception.NotFoundException; import lombok.*; import java.time.LocalDateTime; +import java.util.List; @NoArgsConstructor @AllArgsConstructor @@ -16,11 +24,48 @@ public class CardResponseDTO { private Boolean isActive; private String createdAt; + private List images; + private String name; + private int age; + + private String address; + private Gender gender; + + private String jobName; + private String jobPart; + private String jobLocation; + + private String eduName; + private String eduMajor; + private String eduLevel; + + private String appeal; + + public static CardResponseDTO of(Card card) { + if (card.getTarget() == null) { + throw new NotFoundException(ErrorCode.USER_NOT_FOUND); + } + + //상대 프로필 dto 에서 가져옴 + MemberOppositeProfileResponseDTO dto = MemberOppositeProfileResponseDTO.of(card.getTarget()); + return CardResponseDTO.builder() .targetId(card.getTargetId()) .isActive(card.getIsActive()) .createdAt(card.getCreatedAt().toString()) + .images(card.getTarget().getDetail().getImages()) + .name(dto.getName()) + .age(dto.getAge()) + .address(dto.getAddress()) + .jobName(dto.getJobName()) + .jobPart(dto.getJobPart()) + .jobLocation(dto.getJobLocation()) + .eduName(dto.getEduName()) + .eduMajor(dto.getEduMajor()) + .eduLevel(dto.getEduLevel()) + .gender(dto.getGender()) + .appeal(dto.getAppeal()) .build(); } diff --git a/src/main/java/com/tikitaka/naechinso/domain/card/entity/Card.java b/src/main/java/com/tikitaka/naechinso/domain/card/entity/Card.java index f7eafc0..5557141 100644 --- a/src/main/java/com/tikitaka/naechinso/domain/card/entity/Card.java +++ b/src/main/java/com/tikitaka/naechinso/domain/card/entity/Card.java @@ -30,6 +30,11 @@ public class Card extends BaseEntity { @JsonIgnore private Member member; + @ManyToOne(fetch = FetchType.LAZY) + @JoinColumn(name = "car_target") + @JsonIgnore + private Member target; + @Column(name = "car_target_id") private Long targetId; diff --git a/src/main/java/com/tikitaka/naechinso/domain/member/MemberRepository.java b/src/main/java/com/tikitaka/naechinso/domain/member/MemberRepository.java index e40c848..83db4f3 100644 --- a/src/main/java/com/tikitaka/naechinso/domain/member/MemberRepository.java +++ b/src/main/java/com/tikitaka/naechinso/domain/member/MemberRepository.java @@ -17,7 +17,7 @@ public interface MemberRepository extends JpaRepository { Optional findByPhone(String phone); - Optional findTopByIdNotInAndGenderNot(Collection ids, Gender gender); + Optional findTopByIdNotInAndGenderNotAndDetailNotNull(Collection ids, Gender gender); @Query("SELECT m FROM Member m WHERE m = :member") Optional findByMember(Member member); diff --git a/src/main/java/com/tikitaka/naechinso/domain/member/MemberService.java b/src/main/java/com/tikitaka/naechinso/domain/member/MemberService.java index fbca9a5..43377aa 100644 --- a/src/main/java/com/tikitaka/naechinso/domain/member/MemberService.java +++ b/src/main/java/com/tikitaka/naechinso/domain/member/MemberService.java @@ -196,8 +196,8 @@ public Member findById(Long memberId) { /** 이미 추천받은 카드들에 있는 유저 ID 에 해당하지 않으며 * 매개변수 성별과 값이 다른 유저 한명을 가져온다 */ - public Member findTopByIdNotInAndGenderNot(Collection ids, Gender gender) { - return memberRepository.findTopByIdNotInAndGenderNot(ids, gender) + public Member findTopByIdNotInAndGenderNotAndDetailNotNull(Collection ids, Gender gender) { + return memberRepository.findTopByIdNotInAndGenderNotAndDetailNotNull(ids, gender) .orElseThrow(() -> new NotFoundException(ErrorCode.RANDOM_USER_NOT_FOUND)); } diff --git a/src/main/java/com/tikitaka/naechinso/domain/member/dto/MemberOppositeProfileResponseDTO.java b/src/main/java/com/tikitaka/naechinso/domain/member/dto/MemberOppositeProfileResponseDTO.java index 7c925b0..b745753 100644 --- a/src/main/java/com/tikitaka/naechinso/domain/member/dto/MemberOppositeProfileResponseDTO.java +++ b/src/main/java/com/tikitaka/naechinso/domain/member/dto/MemberOppositeProfileResponseDTO.java @@ -58,7 +58,7 @@ public static MemberOppositeProfileResponseDTO of(Member member) { MemberDetail detail = member.getDetail(); //디테일 없는 유저로 시도 if (detail == null) { - throw new NotFoundException(ErrorCode.USER_NOT_FOUND); + throw new NotFoundException(ErrorCode.USER_NOT_SIGNED_UP); } //추천받은 적 없는 유저를 가져오는 것을 시도 @@ -136,4 +136,9 @@ private static String hideName(String name) { } return name; } + + public String getAppeal() { + return this.recommend.getAppeal(); + } + } diff --git a/src/main/java/com/tikitaka/naechinso/global/error/ErrorCode.java b/src/main/java/com/tikitaka/naechinso/global/error/ErrorCode.java index 88e546c..996aa65 100644 --- a/src/main/java/com/tikitaka/naechinso/global/error/ErrorCode.java +++ b/src/main/java/com/tikitaka/naechinso/global/error/ErrorCode.java @@ -51,6 +51,7 @@ public enum ErrorCode { DUPLICATE_PENDING_REQUEST(BAD_REQUEST, "U005","동일한 종류의 심사 요청은 한 번만 보낼 수 있습니다"), RANDOM_USER_NOT_FOUND(NOT_FOUND, "U006","추천할 수 있는 유저가 더 이상 없습니다"), FORBIDDEN_PROFILE(NOT_FOUND, "U007","해당 유저 프로필에 대한 접근 권한이 없습니다"), + USER_NOT_SIGNED_UP(NOT_FOUND, "U008","정회원으로 가입된 유저가 아닙니다"), /* Recommend 관련 오류 */ From 24bd2113bdad052110f21bd659c3e34749097504 Mon Sep 17 00:00:00 2001 From: gengminy Date: Wed, 19 Oct 2022 15:59:57 +0900 Subject: [PATCH 32/72] =?UTF-8?q?:hammer:=20fix(card):=20=EC=B6=94?= =?UTF-8?q?=EC=B2=9C=20=EC=B9=B4=EB=93=9C=20DTO=20=ED=95=84=EB=93=9C=20?= =?UTF-8?q?=EC=88=98=EC=A0=95=20#41?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../naechinso/domain/TestController.java | 10 +-- .../naechinso/domain/card/CardController.java | 14 ++-- .../naechinso/domain/card/CardRepository.java | 8 +-- .../naechinso/domain/card/CardService.java | 13 ++-- .../domain/card/dto/CardResponseDTO.java | 52 +------------- .../card/dto/CardThumbnailResponseDTO.java | 67 +++++++++++++++++++ .../naechinso/domain/card/entity/Card.java | 9 +-- .../domain/member/MemberService.java | 2 +- .../dto/MemberOppositeProfileResponseDTO.java | 20 +++++- .../domain/recommend/entity/Recommend.java | 10 +++ .../naechinso/global/error/ErrorCode.java | 2 +- 11 files changed, 129 insertions(+), 78 deletions(-) create mode 100644 src/main/java/com/tikitaka/naechinso/domain/card/dto/CardThumbnailResponseDTO.java diff --git a/src/main/java/com/tikitaka/naechinso/domain/TestController.java b/src/main/java/com/tikitaka/naechinso/domain/TestController.java index 287e944..42cc20b 100644 --- a/src/main/java/com/tikitaka/naechinso/domain/TestController.java +++ b/src/main/java/com/tikitaka/naechinso/domain/TestController.java @@ -399,7 +399,9 @@ public CommonApiResponse createMultipleMembers() { Arrays.asList("01022299999", 25, Gender.W, "진하수", "edu-image020.jpg", "연세", "대학교", "기계공학과", "1~3년", "CMC에서 만남", "착함", "자기관리, 귀여워, 차분해", "자기 일을 진짜 책임감 있게 잘하고 주변을 늘 먼저 생각하는 친구야", "서울시 마포구", "1병", 163, "내친소 사용하기", "profile-001-01.png,profile-001-02.png,profile-001-03.png", "반갑습니다 내친소 여러분!", "ESTJ", "열정적인, 상냥한, 섬세한", "무교", "비흡연자", "같이 취미를 즐길 수 있는 연애를 하고 싶어") ); - joinRequestList.forEach(info -> { + String accessToken = null; + + for (List info : joinRequestList) { MemberCommonJoinResponseDTO senderDTO = memberService.joinCommonMember( (String) info.get(0), MemberCommonJoinRequestDTO.builder() @@ -458,8 +460,8 @@ public CommonApiResponse createMultipleMembers() { ); - System.out.println(senderDTO.getAccessToken()); - }); - return CommonApiResponse.of(true); + accessToken = senderDTO.getAccessToken(); + } + return CommonApiResponse.of(accessToken); } } diff --git a/src/main/java/com/tikitaka/naechinso/domain/card/CardController.java b/src/main/java/com/tikitaka/naechinso/domain/card/CardController.java index 2753b00..7a82982 100644 --- a/src/main/java/com/tikitaka/naechinso/domain/card/CardController.java +++ b/src/main/java/com/tikitaka/naechinso/domain/card/CardController.java @@ -1,5 +1,7 @@ package com.tikitaka.naechinso.domain.card; +import com.tikitaka.naechinso.domain.card.dto.CardResponseDTO; +import com.tikitaka.naechinso.domain.card.dto.CardThumbnailResponseDTO; import com.tikitaka.naechinso.domain.match.MatchService; import com.tikitaka.naechinso.domain.match.dto.MatchListResponseDTO; import com.tikitaka.naechinso.domain.member.entity.Member; @@ -12,6 +14,8 @@ import org.springframework.web.bind.annotation.*; import springfox.documentation.annotations.ApiIgnore; +import java.util.List; + @Slf4j @RestController @RequestMapping("/card") @@ -21,7 +25,7 @@ public class CardController { @GetMapping @ApiOperation(value = "자신이 소유한 모든 카드를 가져온다 (AccessToken)") - public CommonApiResponse getAllCardsByMember( + public CommonApiResponse> getAllCardsByMember( @ApiIgnore @AuthMember Member member ) { return CommonApiResponse.of(cardService.findAllDTOByMember(member)); @@ -29,7 +33,7 @@ public CommonApiResponse getAllCardsByMember( @GetMapping("/find") @ApiOperation(value = "[Admin]존재하는 모든 카드를 가져온다 (AccessToken)") - public CommonApiResponse getAllCards( + public CommonApiResponse> getAllCards( @ApiIgnore @AuthMember Member member ) { return CommonApiResponse.of(cardService.findAllDTO()); @@ -38,15 +42,15 @@ public CommonApiResponse getAllCards( @PostMapping @ApiOperation(value = "새로운 카드를 하나 생성한다 (AccessToken)") - public CommonApiResponse createCardByMember( + public CommonApiResponse createCardByMember( @ApiIgnore @AuthMember Member member ) { return CommonApiResponse.of(cardService.createRandomCard(member)); } - @PatchMapping + @PatchMapping("/reject") @ApiOperation(value = "현재 활성화된 카드를 거절한다 (AccessToken)") - public CommonApiResponse rejectCardByMember( + public CommonApiResponse rejectCardByMember( @ApiIgnore @AuthMember Member member ) { return CommonApiResponse.of(cardService.rejectCard(member)); diff --git a/src/main/java/com/tikitaka/naechinso/domain/card/CardRepository.java b/src/main/java/com/tikitaka/naechinso/domain/card/CardRepository.java index 794289d..8a47e10 100644 --- a/src/main/java/com/tikitaka/naechinso/domain/card/CardRepository.java +++ b/src/main/java/com/tikitaka/naechinso/domain/card/CardRepository.java @@ -19,18 +19,18 @@ public interface CardRepository extends JpaRepository { Optional findByMemberAndIsActiveTrue(Member member); Boolean existsByMemberAndIsActiveTrue(Member member); - @Query("select c.targetId " + + @Query("select c.targetMemberId " + "from Card c " + - "where c.targetId <> :id") + "where c.targetMemberId <> :id") List findTargetIdsByIdNot(Long id); - @Query("select new com.tikitaka.naechinso.domain.card.dto.CardResponseDTO(c.targetId, c.isActive, c.createdAt) " + + @Query("select new com.tikitaka.naechinso.domain.card.dto.CardResponseDTO(c.targetMemberId, c.isActive, c.createdAt) " + "from Card c " + "join c.member m " + "where m = :member") List findAllDTOByMember(Member member); - @Query("select new com.tikitaka.naechinso.domain.card.dto.CardResponseDTO(c.targetId, c.isActive, c.createdAt) " + + @Query("select new com.tikitaka.naechinso.domain.card.dto.CardResponseDTO(c.targetMemberId, c.isActive, c.createdAt) " + "from Card c " + "join c.member m") List findAllDTO(); diff --git a/src/main/java/com/tikitaka/naechinso/domain/card/CardService.java b/src/main/java/com/tikitaka/naechinso/domain/card/CardService.java index e91773e..812a207 100644 --- a/src/main/java/com/tikitaka/naechinso/domain/card/CardService.java +++ b/src/main/java/com/tikitaka/naechinso/domain/card/CardService.java @@ -1,6 +1,7 @@ package com.tikitaka.naechinso.domain.card; import com.tikitaka.naechinso.domain.card.dto.CardResponseDTO; +import com.tikitaka.naechinso.domain.card.dto.CardThumbnailResponseDTO; import com.tikitaka.naechinso.domain.card.entity.Card; import com.tikitaka.naechinso.domain.member.MemberRepository; import com.tikitaka.naechinso.domain.member.MemberService; @@ -44,8 +45,9 @@ public class CardService { /** * 추천 받았던 유저를 필터링한 랜덤 추천 카드를 만든다 + * @// TODO: 2022/10/19 3번 횟수 제한 기능 추가 * */ - public CardResponseDTO createRandomCard(Member authMember) { + public CardThumbnailResponseDTO createRandomCard(Member authMember) { //아직 ACTIVE 한 카드가 있으면 에러 if (cardRepository.existsByMemberAndIsActiveTrue(authMember)) { throw new BadRequestException(ErrorCode.ACTIVE_CARD_ALREADY_EXIST); @@ -56,23 +58,22 @@ public CardResponseDTO createRandomCard(Member authMember) { Gender memberGender = member.getGender(); //이미 존재하는 카드에 담긴 유저 ID들 - List existTargetMemberIds = member.getCards().stream().map(Card::getTargetId).collect(Collectors.toList()); + List existTargetMemberIds = member.getCards().stream().map(Card::getTargetMemberId).collect(Collectors.toList()); existTargetMemberIds.add(member.getId()); - //새로운 추천 상대 + //추천 받았던 적 없는 새로운 추천 상대 Member newTargetMember = memberRepository.findTopByIdNotInAndGenderNotAndDetailNotNull(existTargetMemberIds, memberGender) .orElseThrow(() -> new NotFoundException(ErrorCode.RANDOM_USER_NOT_FOUND)); Card newCard = Card.builder() .member(member) - .target(newTargetMember) - .targetId(newTargetMember.getId()) + .targetMemberId(newTargetMember.getId()) .isActive(true) .build(); cardRepository.save(newCard); - return CardResponseDTO.of(newCard); + return CardThumbnailResponseDTO.of(newCard, newTargetMember); } diff --git a/src/main/java/com/tikitaka/naechinso/domain/card/dto/CardResponseDTO.java b/src/main/java/com/tikitaka/naechinso/domain/card/dto/CardResponseDTO.java index 115e637..fe85b05 100644 --- a/src/main/java/com/tikitaka/naechinso/domain/card/dto/CardResponseDTO.java +++ b/src/main/java/com/tikitaka/naechinso/domain/card/dto/CardResponseDTO.java @@ -1,18 +1,9 @@ package com.tikitaka.naechinso.domain.card.dto; import com.tikitaka.naechinso.domain.card.entity.Card; -import com.tikitaka.naechinso.domain.match.constant.MatchStatus; -import com.tikitaka.naechinso.domain.member.constant.Gender; -import com.tikitaka.naechinso.domain.member.dto.MemberOppositeProfileResponseDTO; -import com.tikitaka.naechinso.domain.member.entity.Member; -import com.tikitaka.naechinso.domain.member.entity.MemberDetail; -import com.tikitaka.naechinso.global.error.ErrorCode; -import com.tikitaka.naechinso.global.error.exception.BadRequestException; -import com.tikitaka.naechinso.global.error.exception.NotFoundException; import lombok.*; import java.time.LocalDateTime; -import java.util.List; @NoArgsConstructor @AllArgsConstructor @@ -20,57 +11,20 @@ @Builder @ToString public class CardResponseDTO { - private Long targetId; + private Long targetMemberId; private Boolean isActive; private String createdAt; - private List images; - private String name; - private int age; - - private String address; - private Gender gender; - - private String jobName; - private String jobPart; - private String jobLocation; - - private String eduName; - private String eduMajor; - private String eduLevel; - - private String appeal; - - public static CardResponseDTO of(Card card) { - if (card.getTarget() == null) { - throw new NotFoundException(ErrorCode.USER_NOT_FOUND); - } - - //상대 프로필 dto 에서 가져옴 - MemberOppositeProfileResponseDTO dto = MemberOppositeProfileResponseDTO.of(card.getTarget()); - return CardResponseDTO.builder() - .targetId(card.getTargetId()) + .targetMemberId(card.getTargetMemberId()) .isActive(card.getIsActive()) .createdAt(card.getCreatedAt().toString()) - .images(card.getTarget().getDetail().getImages()) - .name(dto.getName()) - .age(dto.getAge()) - .address(dto.getAddress()) - .jobName(dto.getJobName()) - .jobPart(dto.getJobPart()) - .jobLocation(dto.getJobLocation()) - .eduName(dto.getEduName()) - .eduMajor(dto.getEduMajor()) - .eduLevel(dto.getEduLevel()) - .gender(dto.getGender()) - .appeal(dto.getAppeal()) .build(); } public CardResponseDTO(Long id, Boolean isActive, LocalDateTime createdAt){ - this.targetId = id; + this.targetMemberId = id; this.isActive = isActive; this.createdAt = createdAt.toString(); } diff --git a/src/main/java/com/tikitaka/naechinso/domain/card/dto/CardThumbnailResponseDTO.java b/src/main/java/com/tikitaka/naechinso/domain/card/dto/CardThumbnailResponseDTO.java new file mode 100644 index 0000000..3ba5068 --- /dev/null +++ b/src/main/java/com/tikitaka/naechinso/domain/card/dto/CardThumbnailResponseDTO.java @@ -0,0 +1,67 @@ +package com.tikitaka.naechinso.domain.card.dto; + +import com.tikitaka.naechinso.domain.card.entity.Card; +import com.tikitaka.naechinso.domain.member.constant.Gender; +import com.tikitaka.naechinso.domain.member.dto.MemberOppositeProfileResponseDTO; +import com.tikitaka.naechinso.domain.member.entity.Member; +import com.tikitaka.naechinso.global.error.ErrorCode; +import com.tikitaka.naechinso.global.error.exception.NotFoundException; +import lombok.*; + +import java.util.List; + +@NoArgsConstructor +@AllArgsConstructor +@Getter +@Builder +@ToString +public class CardThumbnailResponseDTO { + private Long targetMemberId; + private Boolean isActive; + private String createdAt; + + private List images; + private String name; + private int age; + + private String address; + private Gender gender; + + private String jobName; + private String jobPart; + private String jobLocation; + + private String eduName; + private String eduMajor; + private String eduLevel; + + private String appeal; + + + public static CardThumbnailResponseDTO of(Card card, Member targetMember) { + if (targetMember == null) { + throw new NotFoundException(ErrorCode.USER_NOT_FOUND); + } + + //상대 프로필 dto 에서 가져옴 + MemberOppositeProfileResponseDTO dto = MemberOppositeProfileResponseDTO.of(targetMember); + + return CardThumbnailResponseDTO.builder() + .targetMemberId(card.getTargetMemberId()) + .isActive(card.getIsActive()) + .createdAt(card.getCreatedAt().toString()) + .images(targetMember.getDetail().getImages()) + .name(dto.getName()) + .age(dto.getAge()) + .address(dto.getAddress()) + .jobName(dto.getJobName()) + .jobPart(dto.getJobPart()) + .jobLocation(dto.getJobLocation()) + .eduName(dto.getEduName()) + .eduMajor(dto.getEduMajor()) + .eduLevel(dto.getEduLevel()) + .gender(dto.getGender()) + .appeal(dto.getAppeal()) + .build(); + } +} diff --git a/src/main/java/com/tikitaka/naechinso/domain/card/entity/Card.java b/src/main/java/com/tikitaka/naechinso/domain/card/entity/Card.java index 5557141..e5f98cf 100644 --- a/src/main/java/com/tikitaka/naechinso/domain/card/entity/Card.java +++ b/src/main/java/com/tikitaka/naechinso/domain/card/entity/Card.java @@ -30,13 +30,8 @@ public class Card extends BaseEntity { @JsonIgnore private Member member; - @ManyToOne(fetch = FetchType.LAZY) - @JoinColumn(name = "car_target") - @JsonIgnore - private Member target; - - @Column(name = "car_target_id") - private Long targetId; + @Column(name = "car_target_mem_id") + private Long targetMemberId; @Column(name = "car_is_active") @Builder.Default diff --git a/src/main/java/com/tikitaka/naechinso/domain/member/MemberService.java b/src/main/java/com/tikitaka/naechinso/domain/member/MemberService.java index 43377aa..1dc8600 100644 --- a/src/main/java/com/tikitaka/naechinso/domain/member/MemberService.java +++ b/src/main/java/com/tikitaka/naechinso/domain/member/MemberService.java @@ -102,7 +102,7 @@ public MemberDetailResponseDTO readDetail(Member member) { public MemberOppositeProfileResponseDTO readOppositeMemberDetailAndRecommendById(Member authMember, Long id) { //현재 ACTIVE 한 카드와 요청 id가 같지 않으면 에러 Card activeCard = cardService.findByMemberAndIsActiveTrue(authMember); - Long targetId = activeCard.getTargetId(); + Long targetId = activeCard.getTargetMemberId(); if (!targetId.equals(id)) { throw new ForbiddenException(ErrorCode.FORBIDDEN_PROFILE); } diff --git a/src/main/java/com/tikitaka/naechinso/domain/member/dto/MemberOppositeProfileResponseDTO.java b/src/main/java/com/tikitaka/naechinso/domain/member/dto/MemberOppositeProfileResponseDTO.java index b745753..232f352 100644 --- a/src/main/java/com/tikitaka/naechinso/domain/member/dto/MemberOppositeProfileResponseDTO.java +++ b/src/main/java/com/tikitaka/naechinso/domain/member/dto/MemberOppositeProfileResponseDTO.java @@ -108,16 +108,31 @@ private static class Recommendation { private String name; private Gender gender; private String appeal; - private String appealDetail; + + private String jobName; + private String jobPart; + private String jobLocation; + private String eduName; + private String eduMajor; + private String eduLevel; + private String meet; private String period; + private String appealDetail; public static Recommendation of(Recommend recommend) { + Member sender = recommend.getSender(); return Recommendation.builder() .name(hideName(recommend.getSenderName())) .gender(recommend.getSenderGender()) .appeal(recommend.getReceiverAppeal()) .appealDetail(recommend.getReceiverAppealDetail()) + .eduName(sender.getEduName()) + .eduMajor(sender.getEduMajor()) + .eduLevel(sender.getEduLevel()) + .jobName(sender.getJobName()) + .jobPart(sender.getJobPart()) + .jobLocation(sender.getJobLocation()) .meet(recommend.getReceiverMeet()) .period(recommend.getReceiverPeriod()) .build(); @@ -138,6 +153,9 @@ private static String hideName(String name) { } public String getAppeal() { + if (this.recommend == null) { + return null; + } return this.recommend.getAppeal(); } diff --git a/src/main/java/com/tikitaka/naechinso/domain/recommend/entity/Recommend.java b/src/main/java/com/tikitaka/naechinso/domain/recommend/entity/Recommend.java index 4318d5e..f7f5d59 100644 --- a/src/main/java/com/tikitaka/naechinso/domain/recommend/entity/Recommend.java +++ b/src/main/java/com/tikitaka/naechinso/domain/recommend/entity/Recommend.java @@ -61,6 +61,16 @@ public class Recommend extends BaseEntity { private String senderJobLocation; +// @Column(name = "mem_edu_name") +// private String senderEduName; +// +// @Column(name = "mem_edu_major") +// private String senderEduPart; +// +// @Column(name = "mem_edu_level") +// private String senderEduLevel; + + /* 받는 사람이 아직 가입 안했으면 NULL 일수도 있음 */ @ManyToOne(fetch = FetchType.LAZY) @JsonIgnore diff --git a/src/main/java/com/tikitaka/naechinso/global/error/ErrorCode.java b/src/main/java/com/tikitaka/naechinso/global/error/ErrorCode.java index 996aa65..fa0d124 100644 --- a/src/main/java/com/tikitaka/naechinso/global/error/ErrorCode.java +++ b/src/main/java/com/tikitaka/naechinso/global/error/ErrorCode.java @@ -50,7 +50,7 @@ public enum ErrorCode { NOT_FOLLOW(NOT_FOUND, "U004","팔로우 중이지 않습니다"), DUPLICATE_PENDING_REQUEST(BAD_REQUEST, "U005","동일한 종류의 심사 요청은 한 번만 보낼 수 있습니다"), RANDOM_USER_NOT_FOUND(NOT_FOUND, "U006","추천할 수 있는 유저가 더 이상 없습니다"), - FORBIDDEN_PROFILE(NOT_FOUND, "U007","해당 유저 프로필에 대한 접근 권한이 없습니다"), + FORBIDDEN_PROFILE(FORBIDDEN, "U007","해당 유저 프로필에 대한 접근 권한이 없습니다"), USER_NOT_SIGNED_UP(NOT_FOUND, "U008","정회원으로 가입된 유저가 아닙니다"), From 0e8dfda5d1d6b54354fccf1363b8b71c8677d1aa Mon Sep 17 00:00:00 2001 From: gengminy Date: Sat, 22 Oct 2022 13:59:57 +0900 Subject: [PATCH 33/72] =?UTF-8?q?:rocket:=20feat(card):=20=EC=B6=94?= =?UTF-8?q?=EC=B2=9C=20=EB=A6=AC=ED=94=84=EB=A0=88=EC=8B=9C=203=ED=9A=8C?= =?UTF-8?q?=20=EC=A0=9C=ED=95=9C=20=EC=A0=95=EC=B1=85=20=EC=B6=94=EA=B0=80?= =?UTF-8?q?=20#41?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../naechinso/domain/TestController.java | 32 +++++++++---------- .../naechinso/domain/card/CardController.java | 1 - .../naechinso/domain/card/CardRepository.java | 4 +++ .../naechinso/domain/card/CardService.java | 21 +++++++++--- .../domain/member/MemberController.java | 1 - .../sms/SmsCertificationServiceImpl.java | 1 - .../naechinso/global/error/ErrorCode.java | 1 + 7 files changed, 38 insertions(+), 23 deletions(-) diff --git a/src/main/java/com/tikitaka/naechinso/domain/TestController.java b/src/main/java/com/tikitaka/naechinso/domain/TestController.java index 42cc20b..9d80a7c 100644 --- a/src/main/java/com/tikitaka/naechinso/domain/TestController.java +++ b/src/main/java/com/tikitaka/naechinso/domain/TestController.java @@ -18,15 +18,12 @@ import io.swagger.annotations.ApiOperation; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; -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.springframework.web.bind.annotation.*; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.Collections; -import java.util.List; +import java.time.LocalDate; +import java.time.LocalDateTime; +import java.time.LocalTime; +import java.util.*; /** * 프론트에서 테스트를 원할하게 진행하기 위한 컨트롤러 @@ -342,16 +339,9 @@ public CommonApiResponse createTwoRegularMember() { return CommonApiResponse.of(senderDTO); } - - - @GetMapping("/create-multiple-users") - @ApiOperation(value = "[*TEST*] 멤버 DB를 초기화한 후, 정회원으로 가입한 유저를 남녀 10명씩 생성하고, 멤버 하나의 엑세스 토큰 반환") + @ApiOperation(value = "[*TEST*] 정회원으로 가입한 유저를 남녀 10명씩 생성하고, 그 중 마지막 여성 멤버 하나의 엑세스 토큰 반환") public CommonApiResponse createMultipleMembers() { - - memberRepository.deleteAll(); - recommendRepository.deleteAll(); - List adminMemberInfo = Arrays.asList("01012345678", 25, Gender.M, "노경닉", "edu-image-admin.jpg", "홍익", "대학교", "컴퓨터공학과", "1~3년", "CMC에서 만남", "착함", "자기관리, 귀여워, 차분해", "자기 일을 진짜 책임감 있게 잘하고 주변을 늘 먼저 생각하는 친구야", "서울시 마포구", "1병", 180, "내친소 사용하기", "profile-001-01.png,profile-001-02.png,profile-001-03.png", "반갑습니다 내친소 여러분!", "ESTJ", "열정적인, 상냥한, 섬세한", "무교", "비흡연자", "같이 취미를 즐길 수 있는 연애를 하고 싶어"); //어드민 겸 추천인 Member adminMember = memberService.findByPhone(memberService.joinCommonMember( @@ -464,4 +454,14 @@ public CommonApiResponse createMultipleMembers() { } return CommonApiResponse.of(accessToken); } + + @DeleteMapping("/drop-all-table") + @ApiOperation(value = "[*TEST*] 모든 DB 테이블을 초기화") + public CommonApiResponse dropAllTable(){ + memberRepository.deleteAll(); + memberDetailRepository.deleteAll(); + recommendRepository.deleteAll(); + cardRepository.deleteAll(); + return CommonApiResponse.of(true); + } } diff --git a/src/main/java/com/tikitaka/naechinso/domain/card/CardController.java b/src/main/java/com/tikitaka/naechinso/domain/card/CardController.java index 7a82982..d071857 100644 --- a/src/main/java/com/tikitaka/naechinso/domain/card/CardController.java +++ b/src/main/java/com/tikitaka/naechinso/domain/card/CardController.java @@ -39,7 +39,6 @@ public CommonApiResponse> getAllCards( return CommonApiResponse.of(cardService.findAllDTO()); } - @PostMapping @ApiOperation(value = "새로운 카드를 하나 생성한다 (AccessToken)") public CommonApiResponse createCardByMember( diff --git a/src/main/java/com/tikitaka/naechinso/domain/card/CardRepository.java b/src/main/java/com/tikitaka/naechinso/domain/card/CardRepository.java index 8a47e10..86df46d 100644 --- a/src/main/java/com/tikitaka/naechinso/domain/card/CardRepository.java +++ b/src/main/java/com/tikitaka/naechinso/domain/card/CardRepository.java @@ -8,6 +8,7 @@ import org.springframework.stereotype.Repository; import java.time.LocalDateTime; +import java.util.Date; import java.util.List; import java.util.Optional; @@ -19,6 +20,9 @@ public interface CardRepository extends JpaRepository { Optional findByMemberAndIsActiveTrue(Member member); Boolean existsByMemberAndIsActiveTrue(Member member); + + long countByMemberAndCreatedAtBetween(Member member, LocalDateTime start, LocalDateTime end); + @Query("select c.targetMemberId " + "from Card c " + "where c.targetMemberId <> :id") diff --git a/src/main/java/com/tikitaka/naechinso/domain/card/CardService.java b/src/main/java/com/tikitaka/naechinso/domain/card/CardService.java index 812a207..2d71c3d 100644 --- a/src/main/java/com/tikitaka/naechinso/domain/card/CardService.java +++ b/src/main/java/com/tikitaka/naechinso/domain/card/CardService.java @@ -15,6 +15,9 @@ import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; +import java.time.LocalDate; +import java.time.LocalDateTime; +import java.time.LocalTime; import java.util.Arrays; import java.util.Collection; import java.util.List; @@ -45,19 +48,23 @@ public class CardService { /** * 추천 받았던 유저를 필터링한 랜덤 추천 카드를 만든다 - * @// TODO: 2022/10/19 3번 횟수 제한 기능 추가 * */ public CardThumbnailResponseDTO createRandomCard(Member authMember) { - //아직 ACTIVE 한 카드가 있으면 에러 + //이미 ACTIVE 한 카드가 있으면 에러 if (cardRepository.existsByMemberAndIsActiveTrue(authMember)) { throw new BadRequestException(ErrorCode.ACTIVE_CARD_ALREADY_EXIST); } + //하루에 세 장 이상 추천을 요청할 경우 에러 + if (countCardByMemberAndCreatedAtBetween(authMember) >= 3) { + throw new BadRequestException(ErrorCode.CARD_LIMIT_EXCEED); + } + Member member = memberRepository.findByMember(authMember) .orElseThrow(() -> new NotFoundException(ErrorCode.USER_NOT_FOUND)); Gender memberGender = member.getGender(); - //이미 존재하는 카드에 담긴 유저 ID들 + //이미 존재하는 카드에 담긴 유저 ID들 가져오기 List existTargetMemberIds = member.getCards().stream().map(Card::getTargetMemberId).collect(Collectors.toList()); existTargetMemberIds.add(member.getId()); @@ -76,7 +83,6 @@ public CardThumbnailResponseDTO createRandomCard(Member authMember) { return CardThumbnailResponseDTO.of(newCard, newTargetMember); } - /** * 현재 ACTIVE 한 카드를 모두 거절하고 INACTIVE 상태로 만든다 * */ @@ -101,4 +107,11 @@ public Card findByMemberAndIsActiveTrue(Member member) { return cardRepository.findByMemberAndIsActiveTrue(member) .orElseThrow(() -> new NotFoundException(ErrorCode.ACTIVE_CARD_NOT_FOUND)); } + + private long countCardByMemberAndCreatedAtBetween(Member member) { + //서버 시간으로 00시00분부터 23시59분까지받은 카드 수 종합 + LocalDateTime startDatetime = LocalDateTime.of(LocalDate.now().minusDays(1), LocalTime.of(0,0,0)); + LocalDateTime endDatetime = LocalDateTime.of(LocalDate.now(), LocalTime.of(23,59,59)); + return cardRepository.countByMemberAndCreatedAtBetween(member, startDatetime, endDatetime); + } } diff --git a/src/main/java/com/tikitaka/naechinso/domain/member/MemberController.java b/src/main/java/com/tikitaka/naechinso/domain/member/MemberController.java index 5840a44..6757ea0 100644 --- a/src/main/java/com/tikitaka/naechinso/domain/member/MemberController.java +++ b/src/main/java/com/tikitaka/naechinso/domain/member/MemberController.java @@ -52,7 +52,6 @@ public CommonApiResponse getMemberProfileById( ) { return CommonApiResponse.of(memberService.readOppositeMemberDetailAndRecommendById(member, id)); } - @GetMapping("/detail") @ApiOperation(value = "회원가입 세부 정보를 가져온다 (AccessToken)") public CommonApiResponse getMemberDetail( diff --git a/src/main/java/com/tikitaka/naechinso/domain/sms/SmsCertificationServiceImpl.java b/src/main/java/com/tikitaka/naechinso/domain/sms/SmsCertificationServiceImpl.java index 117d8e7..9819100 100644 --- a/src/main/java/com/tikitaka/naechinso/domain/sms/SmsCertificationServiceImpl.java +++ b/src/main/java/com/tikitaka/naechinso/domain/sms/SmsCertificationServiceImpl.java @@ -29,7 +29,6 @@ @Service @RequiredArgsConstructor public class SmsCertificationServiceImpl implements SmsCertificationService { - private final NaverSmsService naverSmsService; private final RedisService redisService; private final JwtTokenProvider jwtTokenProvider; diff --git a/src/main/java/com/tikitaka/naechinso/global/error/ErrorCode.java b/src/main/java/com/tikitaka/naechinso/global/error/ErrorCode.java index fa0d124..1d964e8 100644 --- a/src/main/java/com/tikitaka/naechinso/global/error/ErrorCode.java +++ b/src/main/java/com/tikitaka/naechinso/global/error/ErrorCode.java @@ -83,6 +83,7 @@ public enum ErrorCode { /* 카드 관련 */ ACTIVE_CARD_NOT_FOUND(NOT_FOUND, "CARD000", "유효한 추천 카드를 찾을 수 없습니다"), ACTIVE_CARD_ALREADY_EXIST(BAD_REQUEST, "CARD001", "추천 카드는 한 장씩만 받을 수 있습니다"), + CARD_LIMIT_EXCEED(BAD_REQUEST, "CARD002", "일일 추천 카드 한도를 초과했습니다"), ; From b3c8499cf285aebc6087a3032aa4600728e97819 Mon Sep 17 00:00:00 2001 From: gengminy Date: Sat, 22 Oct 2022 14:34:49 +0900 Subject: [PATCH 34/72] =?UTF-8?q?:hammer:=20fix(test):=20TestController=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 --- .../java/com/tikitaka/naechinso/domain/TestController.java | 4 ++-- .../com/tikitaka/naechinso/domain/card/CardService.java | 6 +++++- 2 files changed, 7 insertions(+), 3 deletions(-) diff --git a/src/main/java/com/tikitaka/naechinso/domain/TestController.java b/src/main/java/com/tikitaka/naechinso/domain/TestController.java index 9d80a7c..14f491d 100644 --- a/src/main/java/com/tikitaka/naechinso/domain/TestController.java +++ b/src/main/java/com/tikitaka/naechinso/domain/TestController.java @@ -458,10 +458,10 @@ public CommonApiResponse createMultipleMembers() { @DeleteMapping("/drop-all-table") @ApiOperation(value = "[*TEST*] 모든 DB 테이블을 초기화") public CommonApiResponse dropAllTable(){ - memberRepository.deleteAll(); - memberDetailRepository.deleteAll(); recommendRepository.deleteAll(); cardRepository.deleteAll(); + memberDetailRepository.deleteAll(); + memberRepository.deleteAll(); return CommonApiResponse.of(true); } } diff --git a/src/main/java/com/tikitaka/naechinso/domain/card/CardService.java b/src/main/java/com/tikitaka/naechinso/domain/card/CardService.java index 2d71c3d..8d8c5b1 100644 --- a/src/main/java/com/tikitaka/naechinso/domain/card/CardService.java +++ b/src/main/java/com/tikitaka/naechinso/domain/card/CardService.java @@ -48,6 +48,7 @@ public class CardService { /** * 추천 받았던 유저를 필터링한 랜덤 추천 카드를 만든다 + * @// TODO: 2022/10/22 조건에 맞는 타겟 멤버 중에서 랜덤 선택하도록 * */ public CardThumbnailResponseDTO createRandomCard(Member authMember) { //이미 ACTIVE 한 카드가 있으면 에러 @@ -68,7 +69,7 @@ public CardThumbnailResponseDTO createRandomCard(Member authMember) { List existTargetMemberIds = member.getCards().stream().map(Card::getTargetMemberId).collect(Collectors.toList()); existTargetMemberIds.add(member.getId()); - //추천 받았던 적 없는 새로운 추천 상대 + //추천 받았던 적 없는 새로운 추천 상대 ( todo : 이 중에서 랜덤으로 골라야함 ) Member newTargetMember = memberRepository.findTopByIdNotInAndGenderNotAndDetailNotNull(existTargetMemberIds, memberGender) .orElseThrow(() -> new NotFoundException(ErrorCode.RANDOM_USER_NOT_FOUND)); @@ -108,6 +109,9 @@ public Card findByMemberAndIsActiveTrue(Member member) { .orElseThrow(() -> new NotFoundException(ErrorCode.ACTIVE_CARD_NOT_FOUND)); } + /** + * 오늘 날짜를 기준으로 + * */ private long countCardByMemberAndCreatedAtBetween(Member member) { //서버 시간으로 00시00분부터 23시59분까지받은 카드 수 종합 LocalDateTime startDatetime = LocalDateTime.of(LocalDate.now().minusDays(1), LocalTime.of(0,0,0)); From 9815d3664219423164e91754a1fdccde5b266c7a Mon Sep 17 00:00:00 2001 From: gengminy Date: Sat, 22 Oct 2022 17:34:16 +0900 Subject: [PATCH 35/72] =?UTF-8?q?:rocket:=20feat(card):=20=EC=B6=94?= =?UTF-8?q?=EC=B2=9C=20=EC=B9=B4=EB=93=9C=20=EB=9E=9C=EB=8D=A4=20=EC=A0=9C?= =?UTF-8?q?=EA=B3=B5=20=EA=B5=AC=ED=98=84=20#41?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../naechinso/domain/card/CardService.java | 11 ++++++++--- .../domain/match/MatchController.java | 19 +++++++++++++++++++ .../domain/member/MemberRepository.java | 3 ++- .../domain/member/MemberService.java | 12 ++++++------ 4 files changed, 35 insertions(+), 10 deletions(-) diff --git a/src/main/java/com/tikitaka/naechinso/domain/card/CardService.java b/src/main/java/com/tikitaka/naechinso/domain/card/CardService.java index 8d8c5b1..be2f449 100644 --- a/src/main/java/com/tikitaka/naechinso/domain/card/CardService.java +++ b/src/main/java/com/tikitaka/naechinso/domain/card/CardService.java @@ -21,6 +21,7 @@ import java.util.Arrays; import java.util.Collection; import java.util.List; +import java.util.Random; import java.util.stream.Collectors; @Slf4j @@ -69,9 +70,13 @@ public CardThumbnailResponseDTO createRandomCard(Member authMember) { List existTargetMemberIds = member.getCards().stream().map(Card::getTargetMemberId).collect(Collectors.toList()); existTargetMemberIds.add(member.getId()); - //추천 받았던 적 없는 새로운 추천 상대 ( todo : 이 중에서 랜덤으로 골라야함 ) - Member newTargetMember = memberRepository.findTopByIdNotInAndGenderNotAndDetailNotNull(existTargetMemberIds, memberGender) - .orElseThrow(() -> new NotFoundException(ErrorCode.RANDOM_USER_NOT_FOUND)); + //추천 받았던 적 없는 새로운 추천 상대 리스트 + List newTargetMemberList = memberRepository.findByIdNotInAndGenderNotAndDetailNotNull(existTargetMemberIds, memberGender); + if (newTargetMemberList.isEmpty()) { + throw new NotFoundException(ErrorCode.RANDOM_USER_NOT_FOUND); + } + //(0 ~ size) 사이의 랜덤 인덱스 멤버 추출 + Member newTargetMember = newTargetMemberList.get(new Random().nextInt(newTargetMemberList.size())); Card newCard = Card.builder() .member(member) diff --git a/src/main/java/com/tikitaka/naechinso/domain/match/MatchController.java b/src/main/java/com/tikitaka/naechinso/domain/match/MatchController.java index 0146d51..53fff58 100644 --- a/src/main/java/com/tikitaka/naechinso/domain/match/MatchController.java +++ b/src/main/java/com/tikitaka/naechinso/domain/match/MatchController.java @@ -1,5 +1,6 @@ package com.tikitaka.naechinso.domain.match; +import com.tikitaka.naechinso.domain.card.CardService; import com.tikitaka.naechinso.domain.match.dto.MatchListResponseDTO; import com.tikitaka.naechinso.domain.match.dto.MatchResponseDTO; import com.tikitaka.naechinso.domain.member.entity.Member; @@ -9,6 +10,7 @@ import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.PostMapping; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; import springfox.documentation.annotations.ApiIgnore; @@ -19,6 +21,7 @@ @RequiredArgsConstructor public class MatchController { private final MatchService matchService; + private final CardService cardService; @GetMapping @ApiOperation(value = "매칭페이지에 진입 시 자신의 모든 매칭 정보를 가져온다 (AccessToken)") public CommonApiResponse getAllMatchByMember( @@ -26,4 +29,20 @@ public CommonApiResponse getAllMatchByMember( ) { return CommonApiResponse.of(matchService.findAllByMember(member)); } + + @PostMapping("/like/send") + @ApiOperation(value = "현재 활성화된 카드의 상대에게 호감을 보낸다 (AccessToken)") + public CommonApiResponse sendLike( + @ApiIgnore @AuthMember Member member + ) { + return CommonApiResponse.of(matchService.findAllByMember(member)); + } + + @PostMapping("/like/{id}/accept") + @ApiOperation(value = "현재 호감을 보낸 상대를 수락하여 매칭을 성사시킨다 (AccessToken)") + public CommonApiResponse acceptLike( + @ApiIgnore @AuthMember Member member + ) { + return CommonApiResponse.of(matchService.findAllByMember(member)); + } } diff --git a/src/main/java/com/tikitaka/naechinso/domain/member/MemberRepository.java b/src/main/java/com/tikitaka/naechinso/domain/member/MemberRepository.java index 83db4f3..ec54b45 100644 --- a/src/main/java/com/tikitaka/naechinso/domain/member/MemberRepository.java +++ b/src/main/java/com/tikitaka/naechinso/domain/member/MemberRepository.java @@ -17,7 +17,8 @@ public interface MemberRepository extends JpaRepository { Optional findByPhone(String phone); - Optional findTopByIdNotInAndGenderNotAndDetailNotNull(Collection ids, Gender gender); +// Optional findTopByIdNotInAndGenderNotAndDetailNotNull(Collection ids, Gender gender); + List findByIdNotInAndGenderNotAndDetailNotNull(Collection ids, Gender gender); @Query("SELECT m FROM Member m WHERE m = :member") Optional findByMember(Member member); diff --git a/src/main/java/com/tikitaka/naechinso/domain/member/MemberService.java b/src/main/java/com/tikitaka/naechinso/domain/member/MemberService.java index 1dc8600..d08ead4 100644 --- a/src/main/java/com/tikitaka/naechinso/domain/member/MemberService.java +++ b/src/main/java/com/tikitaka/naechinso/domain/member/MemberService.java @@ -23,10 +23,7 @@ import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; -import java.util.Arrays; -import java.util.Collection; -import java.util.List; -import java.util.Optional; +import java.util.*; import java.util.stream.Collectors; @Service @@ -197,8 +194,11 @@ public Member findById(Long memberId) { /** 이미 추천받은 카드들에 있는 유저 ID 에 해당하지 않으며 * 매개변수 성별과 값이 다른 유저 한명을 가져온다 */ public Member findTopByIdNotInAndGenderNotAndDetailNotNull(Collection ids, Gender gender) { - return memberRepository.findTopByIdNotInAndGenderNotAndDetailNotNull(ids, gender) - .orElseThrow(() -> new NotFoundException(ErrorCode.RANDOM_USER_NOT_FOUND)); + List memberList = memberRepository.findByIdNotInAndGenderNotAndDetailNotNull(ids, gender); + if (memberList.isEmpty()) { + throw new NotFoundException(ErrorCode.RANDOM_USER_NOT_FOUND); + } + return memberList.get(new Random().nextInt(memberList.size())); } public boolean existsById(Long memberId) { From c63547b5521b7e468bb3296374ef4a2f1474591d Mon Sep 17 00:00:00 2001 From: gengminy Date: Mon, 24 Oct 2022 15:19:22 +0900 Subject: [PATCH 36/72] =?UTF-8?q?:hammer:=20fix(sms):=20=EA=B0=9C=EB=B0=9C?= =?UTF-8?q?=EC=84=9C=EB=B2=84=20sms=20=EC=A0=95=EC=B1=85=20=EC=9E=84?= =?UTF-8?q?=EC=8B=9C=20=EC=88=98=EC=A0=95=20#43?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../sms/SmsCertificationServiceImpl.java | 23 +++++++++++++------ 1 file changed, 16 insertions(+), 7 deletions(-) diff --git a/src/main/java/com/tikitaka/naechinso/domain/sms/SmsCertificationServiceImpl.java b/src/main/java/com/tikitaka/naechinso/domain/sms/SmsCertificationServiceImpl.java index 9819100..ef6086d 100644 --- a/src/main/java/com/tikitaka/naechinso/domain/sms/SmsCertificationServiceImpl.java +++ b/src/main/java/com/tikitaka/naechinso/domain/sms/SmsCertificationServiceImpl.java @@ -88,15 +88,24 @@ public SmsCertificationSuccessResponseDTO verifyCode(SmsCertificationRequestDTO String code = requestDTO.getCode(); String key = VERIFICATION_PREFIX + phoneNumber; - //redis 에 해당 번호의 키가 없는 경우는 인증번호(3분) 만료로 처리 - if (!redisService.hasKey(key)) { - throw new UnauthorizedException(ErrorCode.EXPIRED_VERIFICATION_CODE); - } - //redis 에 해당 번호의 키와 인증번호가 일치하지 않는 경우 - if (!redisService.getValues(key).equals(code)) { - throw new UnauthorizedException(ErrorCode.MISMATCH_VERIFICATION_CODE); + /** *********** 임시 정책으로 제거 ********* */ + if (springProfile == null || springProfile.equals("prod")) { + /////////////////////////////////// + /////////////////////////////////// + /////////////////////////////////// + + //redis 에 해당 번호의 키가 없는 경우는 인증번호(3분) 만료로 처리 + if (!redisService.hasKey(key)) { + throw new UnauthorizedException(ErrorCode.EXPIRED_VERIFICATION_CODE); + } + + //redis 에 해당 번호의 키와 인증번호가 일치하지 않는 경우 + if (!redisService.getValues(key).equals(code)) { + throw new UnauthorizedException(ErrorCode.MISMATCH_VERIFICATION_CODE); + } } + /** ******************** */ //redis 인증 필터 성공하면 try { From 4e3bb6ba6a2f87534c4e24e856c29b16a90eb725 Mon Sep 17 00:00:00 2001 From: gengminy Date: Wed, 26 Oct 2022 16:00:29 +0900 Subject: [PATCH 37/72] =?UTF-8?q?:hammer:=20fix(card):=20=EC=B9=B4?= =?UTF-8?q?=EB=93=9C=20=EB=B0=98=ED=99=98=20DTO=20=20=ED=95=84=EB=93=9C=20?= =?UTF-8?q?=EC=88=98=EC=A0=95=20#41?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../naechinso/domain/card/CardRepository.java | 3 - .../naechinso/domain/card/CardService.java | 3 +- .../card/dto/CardThumbnailResponseDTO.java | 58 ++++++++++++++- .../domain/match/MatchController.java | 29 ++++++-- .../domain/match/MatchRepository.java | 10 ++- .../naechinso/domain/match/MatchService.java | 29 ++++++-- .../domain/match/dto/MatchResponseDTO.java | 15 +++- .../match/dto/MatchThumbnailResponseDTO.java | 70 +++++++++++++++++++ .../dto/MemberOppositeProfileResponseDTO.java | 10 +-- 9 files changed, 195 insertions(+), 32 deletions(-) create mode 100644 src/main/java/com/tikitaka/naechinso/domain/match/dto/MatchThumbnailResponseDTO.java diff --git a/src/main/java/com/tikitaka/naechinso/domain/card/CardRepository.java b/src/main/java/com/tikitaka/naechinso/domain/card/CardRepository.java index 86df46d..ea71fb6 100644 --- a/src/main/java/com/tikitaka/naechinso/domain/card/CardRepository.java +++ b/src/main/java/com/tikitaka/naechinso/domain/card/CardRepository.java @@ -5,14 +5,11 @@ import com.tikitaka.naechinso.domain.member.entity.Member; import org.springframework.data.jpa.repository.JpaRepository; import org.springframework.data.jpa.repository.Query; -import org.springframework.stereotype.Repository; import java.time.LocalDateTime; -import java.util.Date; import java.util.List; import java.util.Optional; -@Repository public interface CardRepository extends JpaRepository { int countByIsActive(boolean isActive); diff --git a/src/main/java/com/tikitaka/naechinso/domain/card/CardService.java b/src/main/java/com/tikitaka/naechinso/domain/card/CardService.java index be2f449..1da4f4b 100644 --- a/src/main/java/com/tikitaka/naechinso/domain/card/CardService.java +++ b/src/main/java/com/tikitaka/naechinso/domain/card/CardService.java @@ -56,7 +56,6 @@ public CardThumbnailResponseDTO createRandomCard(Member authMember) { if (cardRepository.existsByMemberAndIsActiveTrue(authMember)) { throw new BadRequestException(ErrorCode.ACTIVE_CARD_ALREADY_EXIST); } - //하루에 세 장 이상 추천을 요청할 경우 에러 if (countCardByMemberAndCreatedAtBetween(authMember) >= 3) { throw new BadRequestException(ErrorCode.CARD_LIMIT_EXCEED); @@ -119,7 +118,7 @@ public Card findByMemberAndIsActiveTrue(Member member) { * */ private long countCardByMemberAndCreatedAtBetween(Member member) { //서버 시간으로 00시00분부터 23시59분까지받은 카드 수 종합 - LocalDateTime startDatetime = LocalDateTime.of(LocalDate.now().minusDays(1), LocalTime.of(0,0,0)); + LocalDateTime startDatetime = LocalDateTime.of(LocalDate.now(), LocalTime.of(0,0,0)); LocalDateTime endDatetime = LocalDateTime.of(LocalDate.now(), LocalTime.of(23,59,59)); return cardRepository.countByMemberAndCreatedAtBetween(member, startDatetime, endDatetime); } diff --git a/src/main/java/com/tikitaka/naechinso/domain/card/dto/CardThumbnailResponseDTO.java b/src/main/java/com/tikitaka/naechinso/domain/card/dto/CardThumbnailResponseDTO.java index 3ba5068..7d8e27a 100644 --- a/src/main/java/com/tikitaka/naechinso/domain/card/dto/CardThumbnailResponseDTO.java +++ b/src/main/java/com/tikitaka/naechinso/domain/card/dto/CardThumbnailResponseDTO.java @@ -4,10 +4,13 @@ import com.tikitaka.naechinso.domain.member.constant.Gender; import com.tikitaka.naechinso.domain.member.dto.MemberOppositeProfileResponseDTO; import com.tikitaka.naechinso.domain.member.entity.Member; +import com.tikitaka.naechinso.domain.recommend.entity.Recommend; import com.tikitaka.naechinso.global.error.ErrorCode; import com.tikitaka.naechinso.global.error.exception.NotFoundException; import lombok.*; +import java.time.*; +import java.util.Date; import java.util.List; @NoArgsConstructor @@ -20,10 +23,12 @@ public class CardThumbnailResponseDTO { private Boolean isActive; private String createdAt; + @Builder.Default + private long dueDate = 0L; + private List images; private String name; private int age; - private String address; private Gender gender; @@ -35,8 +40,29 @@ public class CardThumbnailResponseDTO { private String eduMajor; private String eduLevel; - private String appeal; + private Recommendation recommend; + + @AllArgsConstructor + @NoArgsConstructor + @Getter + @Builder + @ToString + private static class Recommendation { + private String name; + private Gender gender; + private String appeal; + private String jobName; + private String jobPart; + private String jobLocation; + private String eduName; + private String eduMajor; + private String eduLevel; + + private String meet; + private String period; + private String appealDetail; + } public static CardThumbnailResponseDTO of(Card card, Member targetMember) { if (targetMember == null) { @@ -50,6 +76,7 @@ public static CardThumbnailResponseDTO of(Card card, Member targetMember) { .targetMemberId(card.getTargetMemberId()) .isActive(card.getIsActive()) .createdAt(card.getCreatedAt().toString()) + .dueDate(generateDueDate(card.getCreatedAt())) .images(targetMember.getDetail().getImages()) .name(dto.getName()) .age(dto.getAge()) @@ -61,7 +88,32 @@ public static CardThumbnailResponseDTO of(Card card, Member targetMember) { .eduMajor(dto.getEduMajor()) .eduLevel(dto.getEduLevel()) .gender(dto.getGender()) - .appeal(dto.getAppeal()) + .recommend(Recommendation.builder() + .name(dto.getRecommend().getName()) + .gender(dto.getRecommend().getGender()) + .appeal(dto.getRecommend().getAppeal()) + .jobName(dto.getRecommend().getJobName()) + .jobLocation(dto.getRecommend().getJobLocation()) + .jobPart(dto.getRecommend().getJobPart()) + .eduName(dto.getRecommend().getEduName()) + .eduMajor(dto.getRecommend().getEduMajor()) + .eduLevel(dto.getRecommend().getEduLevel()) + .meet(dto.getRecommend().getMeet()) + .period(dto.getRecommend().getPeriod()) + .appealDetail(dto.getRecommend().getAppealDetail()) + .build()) .build(); } + + private static long generateDueDate(LocalDateTime createdAt) { + LocalDateTime endDatetime = LocalDateTime.of(createdAt.toLocalDate().plusDays(7), LocalTime.of(23,59,59)); + long dueDate = Duration.between(LocalDateTime.now(), endDatetime).toDays(); + + System.out.println("endDatetime = " + endDatetime); + + if (dueDate < 0) { + return 0; + } + return dueDate; + } } diff --git a/src/main/java/com/tikitaka/naechinso/domain/match/MatchController.java b/src/main/java/com/tikitaka/naechinso/domain/match/MatchController.java index 53fff58..7a30644 100644 --- a/src/main/java/com/tikitaka/naechinso/domain/match/MatchController.java +++ b/src/main/java/com/tikitaka/naechinso/domain/match/MatchController.java @@ -22,25 +22,42 @@ public class MatchController { private final MatchService matchService; private final CardService cardService; - @GetMapping - @ApiOperation(value = "매칭페이지에 진입 시 자신의 모든 매칭 정보를 가져온다 (AccessToken)") + @GetMapping("/from") + @ApiOperation(value = "내가 받은 호감 정보를 가져온다 (AccessToken)") + public CommonApiResponse getAllMatchByMemberFrom( + @ApiIgnore @AuthMember Member member + ) { +// return CommonApiResponse.of(matchService.findAllMatchDTOBySender(member)); + return null; + } + + @GetMapping("/to") + @ApiOperation(value = "내가 보낸 호감 정보를 가져온다 (AccessToken)") + public CommonApiResponse getAllMatchByMemberTo( + @ApiIgnore @AuthMember Member member + ) { + return CommonApiResponse.of(matchService.findAllByMember(member)); + } + + @GetMapping("/complete") + @ApiOperation(value = "서로 호감을 보낸 성사된 매칭 정보를 가져온다 (AccessToken)") public CommonApiResponse getAllMatchByMember( @ApiIgnore @AuthMember Member member ) { return CommonApiResponse.of(matchService.findAllByMember(member)); } - @PostMapping("/like/send") + @PostMapping("/like") @ApiOperation(value = "현재 활성화된 카드의 상대에게 호감을 보낸다 (AccessToken)") - public CommonApiResponse sendLike( + public CommonApiResponse like( @ApiIgnore @AuthMember Member member ) { return CommonApiResponse.of(matchService.findAllByMember(member)); } - @PostMapping("/like/{id}/accept") + @PostMapping("/{id}/accept") @ApiOperation(value = "현재 호감을 보낸 상대를 수락하여 매칭을 성사시킨다 (AccessToken)") - public CommonApiResponse acceptLike( + public CommonApiResponse accept( @ApiIgnore @AuthMember Member member ) { return CommonApiResponse.of(matchService.findAllByMember(member)); diff --git a/src/main/java/com/tikitaka/naechinso/domain/match/MatchRepository.java b/src/main/java/com/tikitaka/naechinso/domain/match/MatchRepository.java index 0ac6ee2..a4e9d7e 100644 --- a/src/main/java/com/tikitaka/naechinso/domain/match/MatchRepository.java +++ b/src/main/java/com/tikitaka/naechinso/domain/match/MatchRepository.java @@ -1,16 +1,22 @@ package com.tikitaka.naechinso.domain.match; +import com.tikitaka.naechinso.domain.match.dto.MatchResponseDTO; import com.tikitaka.naechinso.domain.match.entity.Match; import com.tikitaka.naechinso.domain.member.entity.Member; import org.springframework.data.jpa.repository.JpaRepository; -import org.springframework.stereotype.Repository; +import org.springframework.data.jpa.repository.Query; import java.util.List; import java.util.Optional; -@Repository public interface MatchRepository extends JpaRepository { List findAllByFromMember(Member member); List findAllByToMember(Member member); + + +// @Query("select new com.tikitaka.naechinso.domain.match.dto.MatchResponseDTO(mat, m1, m2) " + +// "from Match mat " + +// "join mat.toMember m1, mat.fromMember m2") +// List findAllDTO(); } diff --git a/src/main/java/com/tikitaka/naechinso/domain/match/MatchService.java b/src/main/java/com/tikitaka/naechinso/domain/match/MatchService.java index 887a138..8a15c02 100644 --- a/src/main/java/com/tikitaka/naechinso/domain/match/MatchService.java +++ b/src/main/java/com/tikitaka/naechinso/domain/match/MatchService.java @@ -1,6 +1,9 @@ package com.tikitaka.naechinso.domain.match; +import com.tikitaka.naechinso.domain.card.CardRepository; +import com.tikitaka.naechinso.domain.card.CardService; import com.tikitaka.naechinso.domain.match.dto.MatchListResponseDTO; +import com.tikitaka.naechinso.domain.match.dto.MatchResponseDTO; import com.tikitaka.naechinso.domain.match.entity.Match; import com.tikitaka.naechinso.domain.member.MemberService; import com.tikitaka.naechinso.domain.member.entity.Member; @@ -18,23 +21,37 @@ @Transactional public class MatchService { private final MatchRepository matchRepository; - private final MemberService memberService; + private final CardService cardService; + /** + * 활성화된 카드에 해당하는 상대에게 호감을 보낸다 + * @param member + * @return + */ + public MatchResponseDTO like(Member member) { + + + return null; + } public MatchListResponseDTO findAllByMember(Member authMember) { return MatchListResponseDTO.of(authMember); } - - /** 모든 매칭 엔티티 인스턴스를 가져온다 */ - public List findAll() { - return matchRepository.findAll(); - } +// /** 모든 매칭 엔티티 인스턴스를 가져온다 */ +// public List findAll() { +// return matchRepository.findAllDTO(); +// } /** 호감을 보내는 쪽 사람의 매칭 정보를 모두 가져온다 */ public List findAllMatchBySender(Member member) { return matchRepository.findAllByFromMember(member); } +// +// /** 호감을 보내는 쪽 사람의 매칭 정보를 모두 가져온다 */ +// public List findAllMatchDTOBySender(Member member) { +// return matchRepository.findAllByFromMember(member); +// } /** 호감을 받는 쪽 사람의 매칭 정보를 모두 가져온다 */ public List findAllMatchByToReceiver(Member member) { diff --git a/src/main/java/com/tikitaka/naechinso/domain/match/dto/MatchResponseDTO.java b/src/main/java/com/tikitaka/naechinso/domain/match/dto/MatchResponseDTO.java index d537872..7231674 100644 --- a/src/main/java/com/tikitaka/naechinso/domain/match/dto/MatchResponseDTO.java +++ b/src/main/java/com/tikitaka/naechinso/domain/match/dto/MatchResponseDTO.java @@ -2,10 +2,13 @@ import com.tikitaka.naechinso.domain.match.constant.MatchStatus; import com.tikitaka.naechinso.domain.match.entity.Match; +import com.tikitaka.naechinso.domain.member.entity.Member; import com.tikitaka.naechinso.global.error.ErrorCode; import com.tikitaka.naechinso.global.error.exception.BadRequestException; +import com.tikitaka.naechinso.global.error.exception.InternalServerException; import com.tikitaka.naechinso.global.error.exception.NotFoundException; import lombok.*; +import org.joda.time.LocalDateTime; @AllArgsConstructor @NoArgsConstructor @@ -18,17 +21,20 @@ public class MatchResponseDTO { private MatchStatus status; + private String phone; + private Long fromMemberId; private Long toMemberId; private String createdAt; + private String dueDate; + public static MatchResponseDTO of(Match match) { if (match.getFromMember() == null || match.getToMember() == null) { throw new NotFoundException(ErrorCode.USER_NOT_FOUND); } - return MatchResponseDTO.builder() .id(match.getId()) .status(match.getStatus()) @@ -37,4 +43,11 @@ public static MatchResponseDTO of(Match match) { .createdAt(match.getCreatedAt().toString()) .build(); } + + public MatchResponseDTO(Match match) { + if (match.getFromMember() == null || match.getToMember() == null) { + throw new NotFoundException(ErrorCode.USER_NOT_FOUND); + } + this.fromMemberId = match.getFromMember().getId(); + } } diff --git a/src/main/java/com/tikitaka/naechinso/domain/match/dto/MatchThumbnailResponseDTO.java b/src/main/java/com/tikitaka/naechinso/domain/match/dto/MatchThumbnailResponseDTO.java new file mode 100644 index 0000000..f99471b --- /dev/null +++ b/src/main/java/com/tikitaka/naechinso/domain/match/dto/MatchThumbnailResponseDTO.java @@ -0,0 +1,70 @@ +package com.tikitaka.naechinso.domain.match.dto; + +import com.tikitaka.naechinso.domain.card.dto.CardThumbnailResponseDTO; +import com.tikitaka.naechinso.domain.card.entity.Card; +import com.tikitaka.naechinso.domain.match.constant.MatchStatus; +import com.tikitaka.naechinso.domain.member.constant.Gender; +import com.tikitaka.naechinso.domain.member.dto.MemberOppositeProfileResponseDTO; +import com.tikitaka.naechinso.domain.member.entity.Member; +import com.tikitaka.naechinso.global.error.ErrorCode; +import com.tikitaka.naechinso.global.error.exception.NotFoundException; +import lombok.*; + +import java.util.List; + +@AllArgsConstructor +@NoArgsConstructor +@Getter +@Builder +@ToString +public class MatchThumbnailResponseDTO { + private Long targetMemberId; + private Boolean isActive; + private String createdAt; + private MatchStatus status; + private int dueDate; + + private List images; + private String name; + private int age; + + private String address; + private Gender gender; + + private String jobName; + private String jobPart; + private String jobLocation; + + private String eduName; + private String eduMajor; + private String eduLevel; + + private String appeal; + + public static MatchThumbnailResponseDTO of(Card card, Member targetMember) { + if (targetMember == null) { + throw new NotFoundException(ErrorCode.USER_NOT_FOUND); + } + + //상대 프로필 dto 에서 가져옴 + MemberOppositeProfileResponseDTO dto = MemberOppositeProfileResponseDTO.of(targetMember); + + return MatchThumbnailResponseDTO.builder() + .targetMemberId(card.getTargetMemberId()) + .isActive(card.getIsActive()) + .createdAt(card.getCreatedAt().toString()) + .images(targetMember.getDetail().getImages()) + .name(dto.getName()) + .age(dto.getAge()) + .address(dto.getAddress()) + .jobName(dto.getJobName()) + .jobPart(dto.getJobPart()) + .jobLocation(dto.getJobLocation()) + .eduName(dto.getEduName()) + .eduMajor(dto.getEduMajor()) + .eduLevel(dto.getEduLevel()) + .gender(dto.getGender()) +// .appeal(dto.getAppeal()) + .build(); + } +} diff --git a/src/main/java/com/tikitaka/naechinso/domain/member/dto/MemberOppositeProfileResponseDTO.java b/src/main/java/com/tikitaka/naechinso/domain/member/dto/MemberOppositeProfileResponseDTO.java index 232f352..6ba8234 100644 --- a/src/main/java/com/tikitaka/naechinso/domain/member/dto/MemberOppositeProfileResponseDTO.java +++ b/src/main/java/com/tikitaka/naechinso/domain/member/dto/MemberOppositeProfileResponseDTO.java @@ -104,7 +104,7 @@ public static MemberOppositeProfileResponseDTO of(Member member) { @Getter @Builder @ToString - private static class Recommendation { + public static class Recommendation { private String name; private Gender gender; private String appeal; @@ -151,12 +151,4 @@ private static String hideName(String name) { } return name; } - - public String getAppeal() { - if (this.recommend == null) { - return null; - } - return this.recommend.getAppeal(); - } - } From d03d948c56a2f1425c8dd773535d8df05617b683 Mon Sep 17 00:00:00 2001 From: gengminy Date: Wed, 26 Oct 2022 19:14:37 +0900 Subject: [PATCH 38/72] =?UTF-8?q?:rocket:=20feat(match):=20=ED=98=B8?= =?UTF-8?q?=EA=B0=90=20=EB=B3=B4=EB=82=B4=EA=B8=B0=20=EB=B0=8F=20=EC=88=98?= =?UTF-8?q?=EB=9D=BD=20=EA=B5=AC=ED=98=84=20#41?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../naechinso/domain/TestController.java | 31 +++- .../card/dto/CardThumbnailResponseDTO.java | 3 - .../naechinso/domain/card/entity/Card.java | 2 +- .../domain/match/MatchController.java | 43 +++--- .../domain/match/MatchRepository.java | 42 +++++- .../naechinso/domain/match/MatchService.java | 122 +++++++++++++--- .../domain/match/constant/MatchStatus.java | 3 +- .../dto/MatchOppositeProfileResponseDTO.java | 137 ++++++++++++++++++ .../domain/match/dto/MatchResponseDTO.java | 1 - .../match/dto/MatchThumbnailResponseDTO.java | 85 +++++++++-- .../naechinso/domain/match/entity/Match.java | 11 +- .../dto/MemberOppositeProfileResponseDTO.java | 99 ++++++------- .../domain/member/entity/Member.java | 2 +- .../domain/member/entity/MemberDetail.java | 2 +- .../naechinso/global/error/ErrorCode.java | 8 + .../global/util/CustomStringUtil.java | 16 ++ 16 files changed, 482 insertions(+), 125 deletions(-) create mode 100644 src/main/java/com/tikitaka/naechinso/domain/match/dto/MatchOppositeProfileResponseDTO.java create mode 100644 src/main/java/com/tikitaka/naechinso/global/util/CustomStringUtil.java diff --git a/src/main/java/com/tikitaka/naechinso/domain/TestController.java b/src/main/java/com/tikitaka/naechinso/domain/TestController.java index 14f491d..da967ed 100644 --- a/src/main/java/com/tikitaka/naechinso/domain/TestController.java +++ b/src/main/java/com/tikitaka/naechinso/domain/TestController.java @@ -2,6 +2,11 @@ import com.tikitaka.naechinso.domain.card.CardRepository; import com.tikitaka.naechinso.domain.card.CardService; +import com.tikitaka.naechinso.domain.match.MatchRepository; +import com.tikitaka.naechinso.domain.match.MatchService; +import com.tikitaka.naechinso.domain.match.constant.MatchStatus; +import com.tikitaka.naechinso.domain.match.dto.MatchResponseDTO; +import com.tikitaka.naechinso.domain.match.entity.Match; import com.tikitaka.naechinso.domain.member.MemberDetailRepository; import com.tikitaka.naechinso.domain.member.MemberRepository; import com.tikitaka.naechinso.domain.member.MemberService; @@ -14,11 +19,13 @@ import com.tikitaka.naechinso.domain.recommend.RecommendService; import com.tikitaka.naechinso.domain.recommend.dto.RecommendBySenderRequestDTO; import com.tikitaka.naechinso.domain.recommend.dto.RecommendResponseDTO; +import com.tikitaka.naechinso.global.annotation.AuthMember; import com.tikitaka.naechinso.global.config.CommonApiResponse; import io.swagger.annotations.ApiOperation; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; import org.springframework.web.bind.annotation.*; +import springfox.documentation.annotations.ApiIgnore; import java.time.LocalDate; import java.time.LocalDateTime; @@ -42,8 +49,10 @@ public class TestController { private final PendingService pendingService; private final CardService cardService; private final CardRepository cardRepository; + private final MatchService matchService; + private final MatchRepository matchRepository; - @GetMapping("/request-member") + @GetMapping("/create-recommend-request-member") @ApiOperation(value = "[*TEST*] 추천사를 요청하는 유저를 생성하고 엑세스 토큰을 반환한다") public CommonApiResponse generateRecommendRequestUser( ) { @@ -66,8 +75,8 @@ public CommonApiResponse generateRecommendRequestUser( return CommonApiResponse.of(responseDTO); } - @GetMapping("/recommend-send") - @ApiOperation(value = "[*TEST*] 추천사를 요청하는 유저를 생성하고 엑세스 토큰을 반환한다") + @GetMapping("/create-recommend-received-member") + @ApiOperation(value = "[*TEST*] 추천사를 받은 멤버를 임시 유저로 가입시킨 후 엑세스 토큰을 반환한다") public CommonApiResponse generateRecommendReceiver( ) { @@ -455,6 +464,22 @@ public CommonApiResponse createMultipleMembers() { return CommonApiResponse.of(accessToken); } + @GetMapping("/create-match") + @ApiOperation(value = "[*TEST*] 나에게 호감을 보낸 매칭을 하나 생성한다") + public CommonApiResponse dropAllTable( + @ApiIgnore @AuthMember Member member + ) { + Match match = Match.builder() + .fromMember(memberService.findById(20L)) + .toMember(memberService.findByMember(member)) + .status(MatchStatus.PENDING) + .build(); + + matchRepository.save(match); + + return CommonApiResponse.of(MatchResponseDTO.of(match)); + } + @DeleteMapping("/drop-all-table") @ApiOperation(value = "[*TEST*] 모든 DB 테이블을 초기화") public CommonApiResponse dropAllTable(){ diff --git a/src/main/java/com/tikitaka/naechinso/domain/card/dto/CardThumbnailResponseDTO.java b/src/main/java/com/tikitaka/naechinso/domain/card/dto/CardThumbnailResponseDTO.java index 7d8e27a..e059cdb 100644 --- a/src/main/java/com/tikitaka/naechinso/domain/card/dto/CardThumbnailResponseDTO.java +++ b/src/main/java/com/tikitaka/naechinso/domain/card/dto/CardThumbnailResponseDTO.java @@ -108,9 +108,6 @@ public static CardThumbnailResponseDTO of(Card card, Member targetMember) { private static long generateDueDate(LocalDateTime createdAt) { LocalDateTime endDatetime = LocalDateTime.of(createdAt.toLocalDate().plusDays(7), LocalTime.of(23,59,59)); long dueDate = Duration.between(LocalDateTime.now(), endDatetime).toDays(); - - System.out.println("endDatetime = " + endDatetime); - if (dueDate < 0) { return 0; } diff --git a/src/main/java/com/tikitaka/naechinso/domain/card/entity/Card.java b/src/main/java/com/tikitaka/naechinso/domain/card/entity/Card.java index e5f98cf..3753477 100644 --- a/src/main/java/com/tikitaka/naechinso/domain/card/entity/Card.java +++ b/src/main/java/com/tikitaka/naechinso/domain/card/entity/Card.java @@ -12,7 +12,7 @@ * @author gengminy 220924 * */ @Entity -@Table(name = "card") +@Table(name = "Card") @Getter @Builder @AllArgsConstructor diff --git a/src/main/java/com/tikitaka/naechinso/domain/match/MatchController.java b/src/main/java/com/tikitaka/naechinso/domain/match/MatchController.java index 7a30644..961668d 100644 --- a/src/main/java/com/tikitaka/naechinso/domain/match/MatchController.java +++ b/src/main/java/com/tikitaka/naechinso/domain/match/MatchController.java @@ -3,18 +3,18 @@ import com.tikitaka.naechinso.domain.card.CardService; import com.tikitaka.naechinso.domain.match.dto.MatchListResponseDTO; import com.tikitaka.naechinso.domain.match.dto.MatchResponseDTO; +import com.tikitaka.naechinso.domain.match.dto.MatchThumbnailResponseDTO; import com.tikitaka.naechinso.domain.member.entity.Member; import com.tikitaka.naechinso.global.annotation.AuthMember; import com.tikitaka.naechinso.global.config.CommonApiResponse; import io.swagger.annotations.ApiOperation; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; -import org.springframework.web.bind.annotation.GetMapping; -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 springfox.documentation.annotations.ApiIgnore; +import java.util.List; + @Slf4j @RestController @RequestMapping("/match") @@ -22,44 +22,53 @@ public class MatchController { private final MatchService matchService; private final CardService cardService; - @GetMapping("/from") + @GetMapping("/receive") @ApiOperation(value = "내가 받은 호감 정보를 가져온다 (AccessToken)") - public CommonApiResponse getAllMatchByMemberFrom( + public CommonApiResponse> getAllMatchByMemberFrom( @ApiIgnore @AuthMember Member member ) { -// return CommonApiResponse.of(matchService.findAllMatchDTOBySender(member)); - return null; + return CommonApiResponse.of(matchService.findAllByToMember(member)); } - @GetMapping("/to") + @GetMapping("/send") @ApiOperation(value = "내가 보낸 호감 정보를 가져온다 (AccessToken)") - public CommonApiResponse getAllMatchByMemberTo( + public CommonApiResponse> getAllMatchByMemberTo( @ApiIgnore @AuthMember Member member ) { - return CommonApiResponse.of(matchService.findAllByMember(member)); + return CommonApiResponse.of(matchService.findAllByFromMember(member)); } @GetMapping("/complete") @ApiOperation(value = "서로 호감을 보낸 성사된 매칭 정보를 가져온다 (AccessToken)") - public CommonApiResponse getAllMatchByMember( + public CommonApiResponse> getAllCompleteMatchByMember( @ApiIgnore @AuthMember Member member ) { - return CommonApiResponse.of(matchService.findAllByMember(member)); + return CommonApiResponse.of(matchService.findAllByMatchComplete(member)); } @PostMapping("/like") @ApiOperation(value = "현재 활성화된 카드의 상대에게 호감을 보낸다 (AccessToken)") - public CommonApiResponse like( + public CommonApiResponse like( @ApiIgnore @AuthMember Member member ) { - return CommonApiResponse.of(matchService.findAllByMember(member)); + return CommonApiResponse.of(matchService.like(member)); } @PostMapping("/{id}/accept") @ApiOperation(value = "현재 호감을 보낸 상대를 수락하여 매칭을 성사시킨다 (AccessToken)") - public CommonApiResponse accept( + public CommonApiResponse accept( + @PathVariable("id") Long id, + @ApiIgnore @AuthMember Member member + ) { + return CommonApiResponse.of(matchService.accept(member, id)); + } + + @PostMapping("/{id}/open") + @ApiOperation(value = "현재 호감을 보낸 상대의 번호 오픈을 요청한다 (AccessToken)") + public CommonApiResponse openPhone( + @PathVariable("id") Long id, @ApiIgnore @AuthMember Member member ) { - return CommonApiResponse.of(matchService.findAllByMember(member)); + return CommonApiResponse.of(matchService.openPhone(member, id)); } } diff --git a/src/main/java/com/tikitaka/naechinso/domain/match/MatchRepository.java b/src/main/java/com/tikitaka/naechinso/domain/match/MatchRepository.java index a4e9d7e..c5626db 100644 --- a/src/main/java/com/tikitaka/naechinso/domain/match/MatchRepository.java +++ b/src/main/java/com/tikitaka/naechinso/domain/match/MatchRepository.java @@ -1,5 +1,6 @@ package com.tikitaka.naechinso.domain.match; +import com.tikitaka.naechinso.domain.match.constant.MatchStatus; import com.tikitaka.naechinso.domain.match.dto.MatchResponseDTO; import com.tikitaka.naechinso.domain.match.entity.Match; import com.tikitaka.naechinso.domain.member.entity.Member; @@ -11,9 +12,46 @@ public interface MatchRepository extends JpaRepository { - List findAllByFromMember(Member member); - List findAllByToMember(Member member); + /* OPEN 이나 ACCEPT 상태가 아닌 것들만 가져와야함 */ + List findAllByFromMemberAndStatusNotIn(Member member, List statusList); + + List findAllByToMemberAndStatusNotIn(Member member, List statusList); + + @Query("SELECT m " + + "FROM Match m " + + "JOIN m.toMember t " + + "WHERE t = :member " + + "AND m.status <> com.tikitaka.naechinso.domain.match.constant.MatchStatus.ACCEPTED " + + "AND m.status <> com.tikitaka.naechinso.domain.match.constant.MatchStatus.OPEN") + List findAllByToMemberNotComplete(Member member); + + @Query("SELECT m " + + "FROM Match m " + + "JOIN m.fromMember f " + + "WHERE f = :member " + + "AND m.status <> com.tikitaka.naechinso.domain.match.constant.MatchStatus.ACCEPTED " + + "AND m.status <> com.tikitaka.naechinso.domain.match.constant.MatchStatus.OPEN") + List findAllByFromMemberNotComplete(Member member); + + @Query("SELECT m " + + "FROM Match m " + + "JOIN m.fromMember f JOIN m.toMember t " + + "WHERE (f = :member OR t = :member) " + + "AND (m.status = com.tikitaka.naechinso.domain.match.constant.MatchStatus.ACCEPTED " + + "OR m.status = com.tikitaka.naechinso.domain.match.constant.MatchStatus.OPEN)") + List findAllByMemberComplete(Member member); + + @Query("SELECT m " + + "FROM Match m " + + "JOIN m.fromMember f JOIN m.toMember t " + + "WHERE m.id = :id AND (f = :member OR t = :member) " + + "AND m.status = com.tikitaka.naechinso.domain.match.constant.MatchStatus.ACCEPTED") + Optional findAllByIdAndMemberAndStatusIsAccept(Long id, Member member); + + Optional findByIdAndToMemberAndStatus(Long id, Member member, MatchStatus status); + + Optional findByIdAndStatus(Long id, MatchStatus status); // @Query("select new com.tikitaka.naechinso.domain.match.dto.MatchResponseDTO(mat, m1, m2) " + // "from Match mat " + diff --git a/src/main/java/com/tikitaka/naechinso/domain/match/MatchService.java b/src/main/java/com/tikitaka/naechinso/domain/match/MatchService.java index 8a15c02..bf3b39e 100644 --- a/src/main/java/com/tikitaka/naechinso/domain/match/MatchService.java +++ b/src/main/java/com/tikitaka/naechinso/domain/match/MatchService.java @@ -2,11 +2,18 @@ import com.tikitaka.naechinso.domain.card.CardRepository; import com.tikitaka.naechinso.domain.card.CardService; +import com.tikitaka.naechinso.domain.card.entity.Card; +import com.tikitaka.naechinso.domain.match.constant.MatchStatus; import com.tikitaka.naechinso.domain.match.dto.MatchListResponseDTO; import com.tikitaka.naechinso.domain.match.dto.MatchResponseDTO; +import com.tikitaka.naechinso.domain.match.dto.MatchThumbnailResponseDTO; import com.tikitaka.naechinso.domain.match.entity.Match; +import com.tikitaka.naechinso.domain.member.MemberRepository; import com.tikitaka.naechinso.domain.member.MemberService; import com.tikitaka.naechinso.domain.member.entity.Member; +import com.tikitaka.naechinso.global.error.ErrorCode; +import com.tikitaka.naechinso.global.error.exception.BadRequestException; +import com.tikitaka.naechinso.global.error.exception.ForbiddenException; import com.tikitaka.naechinso.global.error.exception.NotFoundException; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; @@ -14,47 +21,118 @@ import org.springframework.transaction.annotation.Transactional; import java.util.List; +import java.util.Optional; +import java.util.stream.Collectors; @Slf4j @Service @RequiredArgsConstructor @Transactional public class MatchService { + + private final MemberRepository memberRepository; private final MatchRepository matchRepository; - private final CardService cardService; + private final CardRepository cardRepository; /** * 활성화된 카드에 해당하는 상대에게 호감을 보낸다 - * @param member + * @param authMember * @return */ - public MatchResponseDTO like(Member member) { + public MatchResponseDTO like(Member authMember) { + Card activeCard = cardRepository.findByMemberAndIsActiveTrue(authMember) + .orElseThrow(() -> new NotFoundException(ErrorCode.ACTIVE_CARD_NOT_FOUND)); + + Member targetMember = memberRepository.findById(activeCard.getTargetMemberId()) + .orElseThrow(() -> new NotFoundException(ErrorCode.USER_NOT_FOUND)); + + Match match = Match.builder() + .status(MatchStatus.PENDING) + .fromMember(authMember) + .toMember(targetMember) + .build(); + //카드 비활성화 + activeCard.disable(); - return null; + matchRepository.save(match); + cardRepository.save(activeCard); + + return MatchResponseDTO.of(match); } - public MatchListResponseDTO findAllByMember(Member authMember) { - return MatchListResponseDTO.of(authMember); + + /** + * 활성화된 카드에 해당하는 상대에게 호감을 보낸다 + * @param authMember + * @return + */ + public MatchResponseDTO accept(Member authMember, Long matchId) { + Match match = matchRepository.findByIdAndToMemberAndStatus(matchId, authMember,MatchStatus.PENDING) + .orElseThrow(() -> new NotFoundException(ErrorCode.MATCH_NOT_FOUND)); + + match.accept(); + matchRepository.save(match); + return MatchResponseDTO.of(match); } -// /** 모든 매칭 엔티티 인스턴스를 가져온다 */ -// public List findAll() { -// return matchRepository.findAllDTO(); -// } + /** + * 번호 오픈권을 사용하여 번호를 오픈한다 + * @param authMember + * @return + */ + public MatchResponseDTO openPhone(Member authMember, Long matchId) { + Match match = matchRepository.findByIdAndStatus(matchId, MatchStatus.ACCEPTED) + .orElseThrow(() -> new NotFoundException(ErrorCode.MATCH_NOT_FOUND)); - /** 호감을 보내는 쪽 사람의 매칭 정보를 모두 가져온다 */ - public List findAllMatchBySender(Member member) { - return matchRepository.findAllByFromMember(member); + //유저에게 속하지 않은 매칭에 대한 유효하지 않은 요청 + if (!match.getFromMember().getId().equals(authMember.getId()) + && !match.getToMember().getId().equals(authMember.getId())) { + throw new ForbiddenException(ErrorCode.FORBIDDEN_MATCH); + } + + match.open(); + matchRepository.save(match); + + return MatchResponseDTO.of(match); } -// -// /** 호감을 보내는 쪽 사람의 매칭 정보를 모두 가져온다 */ -// public List findAllMatchDTOBySender(Member member) { -// return matchRepository.findAllByFromMember(member); -// } - - /** 호감을 받는 쪽 사람의 매칭 정보를 모두 가져온다 */ - public List findAllMatchByToReceiver(Member member) { - return matchRepository.findAllByToMember(member); + + + /** + * 호감을 받은 매칭 정보를 모두 가져온다 + * @param authMember + * @return + */ + public List findAllByToMember(Member authMember) { + return matchRepository.findAllByToMemberNotComplete(authMember).stream() + .map(match -> MatchThumbnailResponseDTO.of(match, authMember)) + .collect(Collectors.toList()); + } + + /** + * 호감을 보낸 매칭 정보를 모두 가져온다 + * @param authMember + * @return + */ + public List findAllByFromMember(Member authMember) { + return matchRepository.findAllByFromMemberNotComplete(authMember).stream() + .map(match -> MatchThumbnailResponseDTO.of(match, authMember)) + .collect(Collectors.toList()); + } + + /** + * 호감을 서로 보내어 성사 완료된 매칭 정보를 모두 가져온다 + * @param authMember + * @return + */ + public List findAllByMatchComplete(Member authMember) { + return matchRepository.findAllByMemberComplete(authMember).stream() + .map(match -> MatchThumbnailResponseDTO.of(match, authMember)) + .collect(Collectors.toList()); + } + + + public MatchListResponseDTO findAllByMember(Member authMember) { + return MatchListResponseDTO.of(authMember); } } diff --git a/src/main/java/com/tikitaka/naechinso/domain/match/constant/MatchStatus.java b/src/main/java/com/tikitaka/naechinso/domain/match/constant/MatchStatus.java index e3c1c47..bd95d92 100644 --- a/src/main/java/com/tikitaka/naechinso/domain/match/constant/MatchStatus.java +++ b/src/main/java/com/tikitaka/naechinso/domain/match/constant/MatchStatus.java @@ -5,5 +5,6 @@ public enum MatchStatus { WAIT, //호감 보내기 전 상태 PENDING, //호감을 보낸 상태 ACCEPTED, //상대가 승낙 - REJECTED //상대가 거절 + REJECTED, //상대가 거절 + OPEN //번호를 오픈함 } diff --git a/src/main/java/com/tikitaka/naechinso/domain/match/dto/MatchOppositeProfileResponseDTO.java b/src/main/java/com/tikitaka/naechinso/domain/match/dto/MatchOppositeProfileResponseDTO.java new file mode 100644 index 0000000..577169a --- /dev/null +++ b/src/main/java/com/tikitaka/naechinso/domain/match/dto/MatchOppositeProfileResponseDTO.java @@ -0,0 +1,137 @@ +package com.tikitaka.naechinso.domain.match.dto; + +import com.tikitaka.naechinso.domain.member.constant.Gender; +import com.tikitaka.naechinso.domain.member.entity.Member; +import com.tikitaka.naechinso.domain.member.entity.MemberDetail; +import com.tikitaka.naechinso.domain.recommend.entity.Recommend; +import com.tikitaka.naechinso.global.error.ErrorCode; +import com.tikitaka.naechinso.global.error.exception.InternalServerException; +import com.tikitaka.naechinso.global.error.exception.NotFoundException; +import com.tikitaka.naechinso.global.util.CustomStringUtil; +import lombok.*; + +import java.util.List; + +/** + * 매칭된 상대의 휴대전화를 포함한 프로필을 반환하는 DTO 입니다 + * @author gengminy 221013 + * */ +@AllArgsConstructor +@NoArgsConstructor +@Getter +@Builder +@ToString +public class MatchOppositeProfileResponseDTO { + private List images; + private String name; + private int age; + + private String phone; + private String address; + private Gender gender; + + private String jobName; + private String jobPart; + private String jobLocation; + + private String eduName; + private String eduMajor; + private String eduLevel; + + private String personality; + private String religion; + private int height; + private String smoke; + private String drink; + + private String hobby; + private String style; + private String introduce; + + private String mbti; + private Recommendation recommend; + + @AllArgsConstructor + @NoArgsConstructor + @Getter + @Builder + @ToString + public static class Recommendation { + private String name; + private Gender gender; + private String appeal; + + private String jobName; + private String jobPart; + private String jobLocation; + private String eduName; + private String eduMajor; + private String eduLevel; + + private String meet; + private String period; + private String appealDetail; + } + + public static MatchOppositeProfileResponseDTO of(Member targetMember) { + MemberDetail detail = targetMember.getDetail(); + //디테일 없는 유저로 시도 + if (detail == null) { + throw new NotFoundException(ErrorCode.USER_NOT_SIGNED_UP); + } + + //추천받은 적 없는 유저를 가져오는 것을 시도 + if (targetMember.getRecommendReceived() == null){ + throw new NotFoundException(ErrorCode.RECOMMEND_NOT_FOUND); + } + + try { + for (Recommend recommend : targetMember.getRecommendReceived()) { + //추천 상태 검증 + if (recommend.getSender() != null && recommend.getReceiver() != null) { + return MatchOppositeProfileResponseDTO.builder() + .images(detail.getImages()) + .name(targetMember.getName()) + .phone(targetMember.getPhone()) + .age(targetMember.getAge()) + .address(detail.getAddress()) + .jobName(targetMember.getJobName()) + .jobPart(targetMember.getJobPart()) + .jobLocation(targetMember.getJobLocation()) + .eduName(targetMember.getEduName()) + .eduMajor(targetMember.getEduMajor()) + .eduLevel(targetMember.getEduLevel()) + .gender(targetMember.getGender()) + .personality(detail.getPersonality()) + .religion(detail.getReligion()) + .height(detail.getHeight()) + .smoke(detail.getSmoke()) + .drink(detail.getDrink()) + .hobby(detail.getHobby()) + .style(detail.getStyle()) + .introduce(detail.getIntroduce()) + .mbti(detail.getMbti()) + .recommend(Recommendation.builder() + .name(CustomStringUtil.hideName(recommend.getSenderName())) + .gender(recommend.getSenderGender()) + .appeal(recommend.getReceiverAppeal()) + .appealDetail(recommend.getReceiverAppealDetail()) + .eduName(recommend.getSender().getEduName()) + .eduMajor(recommend.getSender().getEduMajor()) + .eduLevel(recommend.getSender().getEduLevel()) + .jobName(recommend.getSender().getJobName()) + .jobPart(recommend.getSender().getJobPart()) + .jobLocation(recommend.getSender().getJobLocation()) + .meet(recommend.getReceiverMeet()) + .period(recommend.getReceiverPeriod()) + .build()) + .build(); + + } + } + } catch (Exception e) { + throw new InternalServerException(ErrorCode._INTERNAL_SERVER_ERROR); + } + throw new NotFoundException(ErrorCode.RECOMMEND_NOT_FOUND); + } +} diff --git a/src/main/java/com/tikitaka/naechinso/domain/match/dto/MatchResponseDTO.java b/src/main/java/com/tikitaka/naechinso/domain/match/dto/MatchResponseDTO.java index 7231674..3bf93b6 100644 --- a/src/main/java/com/tikitaka/naechinso/domain/match/dto/MatchResponseDTO.java +++ b/src/main/java/com/tikitaka/naechinso/domain/match/dto/MatchResponseDTO.java @@ -22,7 +22,6 @@ public class MatchResponseDTO { private MatchStatus status; private String phone; - private Long fromMemberId; private Long toMemberId; diff --git a/src/main/java/com/tikitaka/naechinso/domain/match/dto/MatchThumbnailResponseDTO.java b/src/main/java/com/tikitaka/naechinso/domain/match/dto/MatchThumbnailResponseDTO.java index f99471b..134a579 100644 --- a/src/main/java/com/tikitaka/naechinso/domain/match/dto/MatchThumbnailResponseDTO.java +++ b/src/main/java/com/tikitaka/naechinso/domain/match/dto/MatchThumbnailResponseDTO.java @@ -3,6 +3,7 @@ import com.tikitaka.naechinso.domain.card.dto.CardThumbnailResponseDTO; import com.tikitaka.naechinso.domain.card.entity.Card; import com.tikitaka.naechinso.domain.match.constant.MatchStatus; +import com.tikitaka.naechinso.domain.match.entity.Match; import com.tikitaka.naechinso.domain.member.constant.Gender; import com.tikitaka.naechinso.domain.member.dto.MemberOppositeProfileResponseDTO; import com.tikitaka.naechinso.domain.member.entity.Member; @@ -10,6 +11,9 @@ import com.tikitaka.naechinso.global.error.exception.NotFoundException; import lombok.*; +import java.time.Duration; +import java.time.LocalDateTime; +import java.time.LocalTime; import java.util.List; @AllArgsConstructor @@ -18,16 +22,17 @@ @Builder @ToString public class MatchThumbnailResponseDTO { + private Long id; private Long targetMemberId; - private Boolean isActive; - private String createdAt; private MatchStatus status; - private int dueDate; + private String createdAt; + + @Builder.Default + private long dueDate = 0L; private List images; private String name; private int age; - private String address; private Gender gender; @@ -39,21 +44,49 @@ public class MatchThumbnailResponseDTO { private String eduMajor; private String eduLevel; - private String appeal; + private Recommendation recommend; - public static MatchThumbnailResponseDTO of(Card card, Member targetMember) { - if (targetMember == null) { - throw new NotFoundException(ErrorCode.USER_NOT_FOUND); + @AllArgsConstructor + @NoArgsConstructor + @Getter + @Builder + @ToString + private static class Recommendation { + private String name; + private Gender gender; + private String appeal; + + private String jobName; + private String jobPart; + private String jobLocation; + private String eduName; + private String eduMajor; + private String eduLevel; + + private String meet; + private String period; + private String appealDetail; + } + + public static MatchThumbnailResponseDTO of(Match match, Member member) { + Member targetMember; + + //매칭 주체에 따라 상대의 정보를 가져옴 + if (member.equals(match.getToMember())) { + System.out.println("member.equals(match.getToMember()) = " + member.equals(match.getToMember())); + targetMember = match.getFromMember(); + } else { + targetMember = match.getToMember(); } - //상대 프로필 dto 에서 가져옴 MemberOppositeProfileResponseDTO dto = MemberOppositeProfileResponseDTO.of(targetMember); - return MatchThumbnailResponseDTO.builder() - .targetMemberId(card.getTargetMemberId()) - .isActive(card.getIsActive()) - .createdAt(card.getCreatedAt().toString()) - .images(targetMember.getDetail().getImages()) + .id(match.getId()) + .targetMemberId(targetMember.getId()) + .status(match.getStatus()) + .createdAt(match.getCreatedAt().toString()) + .dueDate(generateDueDate(match.getCreatedAt())) + .images(dto.getImages()) .name(dto.getName()) .age(dto.getAge()) .address(dto.getAddress()) @@ -64,7 +97,29 @@ public static MatchThumbnailResponseDTO of(Card card, Member targetMember) { .eduMajor(dto.getEduMajor()) .eduLevel(dto.getEduLevel()) .gender(dto.getGender()) -// .appeal(dto.getAppeal()) + .recommend(Recommendation.builder() + .name(dto.getRecommend().getName()) + .gender(dto.getRecommend().getGender()) + .appeal(dto.getRecommend().getAppeal()) + .jobName(dto.getRecommend().getJobName()) + .jobLocation(dto.getRecommend().getJobLocation()) + .jobPart(dto.getRecommend().getJobPart()) + .eduName(dto.getRecommend().getEduName()) + .eduMajor(dto.getRecommend().getEduMajor()) + .eduLevel(dto.getRecommend().getEduLevel()) + .meet(dto.getRecommend().getMeet()) + .period(dto.getRecommend().getPeriod()) + .appealDetail(dto.getRecommend().getAppealDetail()) + .build()) .build(); } + + private static long generateDueDate(LocalDateTime createdAt) { + LocalDateTime endDatetime = LocalDateTime.of(createdAt.toLocalDate().plusDays(7), LocalTime.of(23,59,59)); + long dueDate = Duration.between(LocalDateTime.now(), endDatetime).toDays(); + if (dueDate < 0) { + return 0; + } + return dueDate; + } } diff --git a/src/main/java/com/tikitaka/naechinso/domain/match/entity/Match.java b/src/main/java/com/tikitaka/naechinso/domain/match/entity/Match.java index 0b91abd..3f0f81c 100644 --- a/src/main/java/com/tikitaka/naechinso/domain/match/entity/Match.java +++ b/src/main/java/com/tikitaka/naechinso/domain/match/entity/Match.java @@ -9,7 +9,7 @@ import javax.persistence.*; @Entity -@Table(name = "match") +@Table(name = "Match") @Getter @Builder @AllArgsConstructor @@ -39,4 +39,13 @@ public class Match extends BaseEntity { @JsonIgnore private Member toMember; + /* 서로 호감을 보내어 매칭 수락 */ + public void accept() { + this.status = MatchStatus.ACCEPTED; + } + /* 번호 오픈권 사용 */ + public void open() { + this.status = MatchStatus.OPEN; + } + } diff --git a/src/main/java/com/tikitaka/naechinso/domain/member/dto/MemberOppositeProfileResponseDTO.java b/src/main/java/com/tikitaka/naechinso/domain/member/dto/MemberOppositeProfileResponseDTO.java index 6ba8234..98ed25f 100644 --- a/src/main/java/com/tikitaka/naechinso/domain/member/dto/MemberOppositeProfileResponseDTO.java +++ b/src/main/java/com/tikitaka/naechinso/domain/member/dto/MemberOppositeProfileResponseDTO.java @@ -8,6 +8,7 @@ import com.tikitaka.naechinso.global.error.ErrorCode; import com.tikitaka.naechinso.global.error.exception.BadRequestException; import com.tikitaka.naechinso.global.error.exception.NotFoundException; +import com.tikitaka.naechinso.global.util.CustomStringUtil; import lombok.*; import org.springframework.security.core.parameters.P; @@ -49,11 +50,49 @@ public class MemberOppositeProfileResponseDTO { private String style; private String introduce; - private String mbti; - private Recommendation recommend; + @AllArgsConstructor + @NoArgsConstructor + @Getter + @Builder + @ToString + public static class Recommendation { + private String name; + private Gender gender; + private String appeal; + + private String jobName; + private String jobPart; + private String jobLocation; + private String eduName; + private String eduMajor; + private String eduLevel; + + private String meet; + private String period; + private String appealDetail; + + public static Recommendation of(Recommend recommend) { + Member sender = recommend.getSender(); + return Recommendation.builder() + .name(CustomStringUtil.hideName(recommend.getSenderName())) + .gender(recommend.getSenderGender()) + .appeal(recommend.getReceiverAppeal()) + .appealDetail(recommend.getReceiverAppealDetail()) + .eduName(sender.getEduName()) + .eduMajor(sender.getEduMajor()) + .eduLevel(sender.getEduLevel()) + .jobName(sender.getJobName()) + .jobPart(sender.getJobPart()) + .jobLocation(sender.getJobLocation()) + .meet(recommend.getReceiverMeet()) + .period(recommend.getReceiverPeriod()) + .build(); + } + } + public static MemberOppositeProfileResponseDTO of(Member member) { MemberDetail detail = member.getDetail(); //디테일 없는 유저로 시도 @@ -71,7 +110,7 @@ public static MemberOppositeProfileResponseDTO of(Member member) { if (recommend.getSender() != null && recommend.getReceiver() != null) { return MemberOppositeProfileResponseDTO.builder() .images(detail.getImages()) - .name(hideName(member.getName())) + .name(CustomStringUtil.hideName(member.getName())) .age(member.getAge()) .address(detail.getAddress()) .jobName(member.getJobName()) @@ -97,58 +136,4 @@ public static MemberOppositeProfileResponseDTO of(Member member) { } throw new NotFoundException(ErrorCode.RECOMMEND_NOT_FOUND); } - - - @AllArgsConstructor - @NoArgsConstructor - @Getter - @Builder - @ToString - public static class Recommendation { - private String name; - private Gender gender; - private String appeal; - - private String jobName; - private String jobPart; - private String jobLocation; - private String eduName; - private String eduMajor; - private String eduLevel; - - private String meet; - private String period; - private String appealDetail; - - public static Recommendation of(Recommend recommend) { - Member sender = recommend.getSender(); - return Recommendation.builder() - .name(hideName(recommend.getSenderName())) - .gender(recommend.getSenderGender()) - .appeal(recommend.getReceiverAppeal()) - .appealDetail(recommend.getReceiverAppealDetail()) - .eduName(sender.getEduName()) - .eduMajor(sender.getEduMajor()) - .eduLevel(sender.getEduLevel()) - .jobName(sender.getJobName()) - .jobPart(sender.getJobPart()) - .jobLocation(sender.getJobLocation()) - .meet(recommend.getReceiverMeet()) - .period(recommend.getReceiverPeriod()) - .build(); - } - } - - private static String hideName(String name) { - if (name.length() == 1) { - return "*"; - } else if (name.length() == 2) { - return name.charAt(0) + "*"; - } else if (name.length() > 2) { - return name.charAt(0) - + "*".repeat(name.length() - 2) - + name.charAt(name.length() - 1); - } - return name; - } } diff --git a/src/main/java/com/tikitaka/naechinso/domain/member/entity/Member.java b/src/main/java/com/tikitaka/naechinso/domain/member/entity/Member.java index 5cb8ad4..e148a96 100644 --- a/src/main/java/com/tikitaka/naechinso/domain/member/entity/Member.java +++ b/src/main/java/com/tikitaka/naechinso/domain/member/entity/Member.java @@ -25,7 +25,7 @@ * @author gengminy 220924 * */ @Entity -@Table(name = "member") +@Table(name = "Member") @Getter @Builder @AllArgsConstructor diff --git a/src/main/java/com/tikitaka/naechinso/domain/member/entity/MemberDetail.java b/src/main/java/com/tikitaka/naechinso/domain/member/entity/MemberDetail.java index fb7c1d6..e111ccd 100644 --- a/src/main/java/com/tikitaka/naechinso/domain/member/entity/MemberDetail.java +++ b/src/main/java/com/tikitaka/naechinso/domain/member/entity/MemberDetail.java @@ -17,7 +17,7 @@ * @author gengminy 220924 * */ @Entity -@Table(name = "member_detail") +@Table(name = "Member_detail") @Getter @Builder @AllArgsConstructor diff --git a/src/main/java/com/tikitaka/naechinso/global/error/ErrorCode.java b/src/main/java/com/tikitaka/naechinso/global/error/ErrorCode.java index 1d964e8..66523b1 100644 --- a/src/main/java/com/tikitaka/naechinso/global/error/ErrorCode.java +++ b/src/main/java/com/tikitaka/naechinso/global/error/ErrorCode.java @@ -65,6 +65,14 @@ public enum ErrorCode { RECOMMEND_SENDER_UNAUTHORIZED(UNAUTHORIZED, "R007","추천인의 인증이 아직 완료되지 않았습니다"), RECOMMEND_SENDER_NOT_EXIST(BAD_REQUEST, "R008","추천인 정보가 올바르지 않습니다"), + + /* Match 오류 */ + MATCH_NOT_FOUND(NOT_FOUND, "MATCH000", "매칭 정보를 찾을 수 없습니다"), + FORBIDDEN_MATCH(FORBIDDEN, "MATCH001", "해당 매칭 정보에 대한 접근 권한이 없습니다"), + MATCH_ALREADY_OPEN(BAD_REQUEST, "MATCH002", "이미 번호 오픈권을 사용했습니다"), + MATCH_ALREADY_ACCEPTED(BAD_REQUEST, "MATCH002", "이미 호감을 수락했습니다"), + BAD_MATCH_STATUS(BAD_REQUEST, "MATCH003", "매칭 상태 정보가 유효하지 않습니다"), + /* Validation 오류 */ PARAMETER_NOT_VALID(BAD_REQUEST, "P000", "인자가 유효하지 않습니다"), diff --git a/src/main/java/com/tikitaka/naechinso/global/util/CustomStringUtil.java b/src/main/java/com/tikitaka/naechinso/global/util/CustomStringUtil.java new file mode 100644 index 0000000..75cf97c --- /dev/null +++ b/src/main/java/com/tikitaka/naechinso/global/util/CustomStringUtil.java @@ -0,0 +1,16 @@ +package com.tikitaka.naechinso.global.util; + +public class CustomStringUtil { + public static String hideName(String name) { + if (name.length() == 1) { + return "*"; + } else if (name.length() == 2) { + return name.charAt(0) + "*"; + } else if (name.length() > 2) { + return name.charAt(0) + + "*".repeat(name.length() - 2) + + name.charAt(name.length() - 1); + } + return name; + } +} From cb1d397b7688f425497f54fb93c0d5179bb09d1f Mon Sep 17 00:00:00 2001 From: gengminy Date: Wed, 26 Oct 2022 20:23:25 +0900 Subject: [PATCH 39/72] =?UTF-8?q?:rocket:=20feat(match):=20=EB=A7=A4?= =?UTF-8?q?=EC=B9=AD=20=EC=83=81=EB=8C=80=20=ED=94=84=EB=A1=9C=ED=95=84=20?= =?UTF-8?q?=EB=B2=88=ED=98=B8=20=EC=98=A4=ED=94=88=20=EA=B5=AC=ED=98=84=20?= =?UTF-8?q?#45?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../naechinso/domain/card/CardController.java | 13 +- .../naechinso/domain/card/CardService.java | 39 +++-- .../CardOppositeMemberProfileResponseDTO.java | 132 +++++++++++++++++ .../domain/match/MatchController.java | 23 ++- .../domain/match/MatchRepository.java | 13 ++ .../naechinso/domain/match/MatchService.java | 39 ++++- .../dto/MatchBasicProfileResponseDTO.java | 134 ++++++++++++++++++ ....java => MatchOpenProfileResponseDTO.java} | 6 +- .../domain/member/MemberController.java | 17 +-- .../domain/member/MemberService.java | 30 ++-- 10 files changed, 388 insertions(+), 58 deletions(-) create mode 100644 src/main/java/com/tikitaka/naechinso/domain/card/dto/CardOppositeMemberProfileResponseDTO.java create mode 100644 src/main/java/com/tikitaka/naechinso/domain/match/dto/MatchBasicProfileResponseDTO.java rename src/main/java/com/tikitaka/naechinso/domain/match/dto/{MatchOppositeProfileResponseDTO.java => MatchOpenProfileResponseDTO.java} (96%) diff --git a/src/main/java/com/tikitaka/naechinso/domain/card/CardController.java b/src/main/java/com/tikitaka/naechinso/domain/card/CardController.java index d071857..a2d8dbd 100644 --- a/src/main/java/com/tikitaka/naechinso/domain/card/CardController.java +++ b/src/main/java/com/tikitaka/naechinso/domain/card/CardController.java @@ -1,16 +1,14 @@ package com.tikitaka.naechinso.domain.card; +import com.tikitaka.naechinso.domain.card.dto.CardOppositeMemberProfileResponseDTO; import com.tikitaka.naechinso.domain.card.dto.CardResponseDTO; import com.tikitaka.naechinso.domain.card.dto.CardThumbnailResponseDTO; -import com.tikitaka.naechinso.domain.match.MatchService; -import com.tikitaka.naechinso.domain.match.dto.MatchListResponseDTO; import com.tikitaka.naechinso.domain.member.entity.Member; import com.tikitaka.naechinso.global.annotation.AuthMember; import com.tikitaka.naechinso.global.config.CommonApiResponse; import io.swagger.annotations.ApiOperation; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; -import org.springframework.stereotype.Controller; import org.springframework.web.bind.annotation.*; import springfox.documentation.annotations.ApiIgnore; @@ -39,6 +37,15 @@ public CommonApiResponse> getAllCards( return CommonApiResponse.of(cardService.findAllDTO()); } + @GetMapping("/{id}/profile") + @ApiOperation(value = "고유 아이디의 유저 프로필과 추천인 정보를 가져온다 (AccessToken)") + public CommonApiResponse getProfileByCardMember( + @PathVariable("id") Long id, + @ApiIgnore @AuthMember Member member + ) { + return CommonApiResponse.of(cardService.findOppositeMemberDetailAndRecommendById(member, id)); + } + @PostMapping @ApiOperation(value = "새로운 카드를 하나 생성한다 (AccessToken)") public CommonApiResponse createCardByMember( diff --git a/src/main/java/com/tikitaka/naechinso/domain/card/CardService.java b/src/main/java/com/tikitaka/naechinso/domain/card/CardService.java index 1da4f4b..5829585 100644 --- a/src/main/java/com/tikitaka/naechinso/domain/card/CardService.java +++ b/src/main/java/com/tikitaka/naechinso/domain/card/CardService.java @@ -1,25 +1,23 @@ package com.tikitaka.naechinso.domain.card; +import com.tikitaka.naechinso.domain.card.dto.CardOppositeMemberProfileResponseDTO; import com.tikitaka.naechinso.domain.card.dto.CardResponseDTO; import com.tikitaka.naechinso.domain.card.dto.CardThumbnailResponseDTO; import com.tikitaka.naechinso.domain.card.entity.Card; import com.tikitaka.naechinso.domain.member.MemberRepository; -import com.tikitaka.naechinso.domain.member.MemberService; import com.tikitaka.naechinso.domain.member.constant.Gender; import com.tikitaka.naechinso.domain.member.entity.Member; import com.tikitaka.naechinso.global.error.ErrorCode; import com.tikitaka.naechinso.global.error.exception.BadRequestException; +import com.tikitaka.naechinso.global.error.exception.ForbiddenException; import com.tikitaka.naechinso.global.error.exception.NotFoundException; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; import org.springframework.stereotype.Service; -import org.springframework.transaction.annotation.Transactional; import java.time.LocalDate; import java.time.LocalDateTime; import java.time.LocalTime; -import java.util.Arrays; -import java.util.Collection; import java.util.List; import java.util.Random; import java.util.stream.Collectors; @@ -32,24 +30,8 @@ public class CardService { private final CardRepository cardRepository; private final MemberRepository memberRepository; -// public CardResponseDTO createCard(Member authMember) { -// -// Member member = memberRepository.findByMember(authMember) -// .orElseThrow(() -> new NotFoundException(ErrorCode.USER_NOT_FOUND)); -// -// Card newCard = Card.builder() -// .member(member) -// .targetId(3L) -// .build(); -// -// cardRepository.save(newCard); -// -// return CardResponseDTO.of(newCard); -// } - /** * 추천 받았던 유저를 필터링한 랜덤 추천 카드를 만든다 - * @// TODO: 2022/10/22 조건에 맞는 타겟 멤버 중에서 랜덤 선택하도록 * */ public CardThumbnailResponseDTO createRandomCard(Member authMember) { //이미 ACTIVE 한 카드가 있으면 에러 @@ -100,6 +82,23 @@ public CardResponseDTO rejectCard(Member authMember) { return CardResponseDTO.of(activeCard); } + /** + * 랜덤 추천받은 상대의 프로필 카드를 가져오는 서비스 로직 + * ACTIVE 한 카드에만 접근 권한이 있음 + * */ + public CardOppositeMemberProfileResponseDTO findOppositeMemberDetailAndRecommendById(Member authMember, Long id) { + //현재 ACTIVE 한 카드와 요청 id가 같지 않으면 에러 + Card activeCard = findByMemberAndIsActiveTrue(authMember); + Long targetId = activeCard.getTargetMemberId(); + if (!targetId.equals(id)) { + throw new ForbiddenException(ErrorCode.FORBIDDEN_PROFILE); + } + + Member oppositeMember = memberRepository.findByMember(authMember) + .orElseThrow(() -> new NotFoundException(ErrorCode.USER_NOT_FOUND)); + return CardOppositeMemberProfileResponseDTO.of(oppositeMember); + } + public List findAllDTOByMember(Member member) { return cardRepository.findAllDTOByMember(member); } diff --git a/src/main/java/com/tikitaka/naechinso/domain/card/dto/CardOppositeMemberProfileResponseDTO.java b/src/main/java/com/tikitaka/naechinso/domain/card/dto/CardOppositeMemberProfileResponseDTO.java new file mode 100644 index 0000000..d6730f6 --- /dev/null +++ b/src/main/java/com/tikitaka/naechinso/domain/card/dto/CardOppositeMemberProfileResponseDTO.java @@ -0,0 +1,132 @@ +package com.tikitaka.naechinso.domain.card.dto; + +import com.tikitaka.naechinso.domain.member.constant.Gender; +import com.tikitaka.naechinso.domain.member.entity.Member; +import com.tikitaka.naechinso.domain.member.entity.MemberDetail; +import com.tikitaka.naechinso.domain.recommend.entity.Recommend; +import com.tikitaka.naechinso.global.error.ErrorCode; +import com.tikitaka.naechinso.global.error.exception.NotFoundException; +import com.tikitaka.naechinso.global.util.CustomStringUtil; +import lombok.*; + +import java.util.List; + +@AllArgsConstructor +@NoArgsConstructor +@Getter +@Builder +@ToString +public class CardOppositeMemberProfileResponseDTO { + + private List images; + private String name; + private int age; + + private String address; + private Gender gender; + + private String jobName; + private String jobPart; + private String jobLocation; + + private String eduName; + private String eduMajor; + private String eduLevel; + + private String personality; + private String religion; + private int height; + private String smoke; + private String drink; + + private String hobby; + private String style; + private String introduce; + + private String mbti; + private Recommendation recommend; + + @AllArgsConstructor + @NoArgsConstructor + @Getter + @Builder + @ToString + public static class Recommendation { + private String name; + private Gender gender; + private String appeal; + + private String jobName; + private String jobPart; + private String jobLocation; + private String eduName; + private String eduMajor; + private String eduLevel; + + private String meet; + private String period; + private String appealDetail; + + public static CardOppositeMemberProfileResponseDTO.Recommendation of(Recommend recommend) { + Member sender = recommend.getSender(); + return CardOppositeMemberProfileResponseDTO.Recommendation.builder() + .name(CustomStringUtil.hideName(recommend.getSenderName())) + .gender(recommend.getSenderGender()) + .appeal(recommend.getReceiverAppeal()) + .appealDetail(recommend.getReceiverAppealDetail()) + .eduName(sender.getEduName()) + .eduMajor(sender.getEduMajor()) + .eduLevel(sender.getEduLevel()) + .jobName(sender.getJobName()) + .jobPart(sender.getJobPart()) + .jobLocation(sender.getJobLocation()) + .meet(recommend.getReceiverMeet()) + .period(recommend.getReceiverPeriod()) + .build(); + } + } + + public static CardOppositeMemberProfileResponseDTO of(Member member) { + MemberDetail detail = member.getDetail(); + //디테일 없는 유저로 시도 + if (detail == null) { + throw new NotFoundException(ErrorCode.USER_NOT_SIGNED_UP); + } + + //추천받은 적 없는 유저를 가져오는 것을 시도 + if (member.getRecommendReceived() == null){ + throw new NotFoundException(ErrorCode.RECOMMEND_NOT_FOUND); + } + + for (Recommend recommend: member.getRecommendReceived()) { + //추천 상태 검증 + if (recommend.getSender() != null && recommend.getReceiver() != null) { + return CardOppositeMemberProfileResponseDTO.builder() + .images(detail.getImages()) + .name(CustomStringUtil.hideName(member.getName())) + .age(member.getAge()) + .address(detail.getAddress()) + .jobName(member.getJobName()) + .jobPart(member.getJobPart()) + .jobLocation(member.getJobLocation()) + .eduName(member.getEduName()) + .eduMajor(member.getEduMajor()) + .eduLevel(member.getEduLevel()) + .gender(member.getGender()) + .personality(detail.getPersonality()) + .religion(detail.getReligion()) + .height(detail.getHeight()) + .smoke(detail.getSmoke()) + .drink(detail.getDrink()) + .hobby(detail.getHobby()) + .style(detail.getStyle()) + .introduce(detail.getIntroduce()) + .mbti(detail.getMbti()) + .recommend(CardOppositeMemberProfileResponseDTO.Recommendation.of(recommend)) + .build(); + + } + } + throw new NotFoundException(ErrorCode.RECOMMEND_NOT_FOUND); + } +} diff --git a/src/main/java/com/tikitaka/naechinso/domain/match/MatchController.java b/src/main/java/com/tikitaka/naechinso/domain/match/MatchController.java index 961668d..8d7573c 100644 --- a/src/main/java/com/tikitaka/naechinso/domain/match/MatchController.java +++ b/src/main/java/com/tikitaka/naechinso/domain/match/MatchController.java @@ -1,7 +1,8 @@ package com.tikitaka.naechinso.domain.match; import com.tikitaka.naechinso.domain.card.CardService; -import com.tikitaka.naechinso.domain.match.dto.MatchListResponseDTO; +import com.tikitaka.naechinso.domain.match.dto.MatchBasicProfileResponseDTO; +import com.tikitaka.naechinso.domain.match.dto.MatchOpenProfileResponseDTO; import com.tikitaka.naechinso.domain.match.dto.MatchResponseDTO; import com.tikitaka.naechinso.domain.match.dto.MatchThumbnailResponseDTO; import com.tikitaka.naechinso.domain.member.entity.Member; @@ -54,10 +55,28 @@ public CommonApiResponse like( return CommonApiResponse.of(matchService.like(member)); } + @GetMapping("/{memberId}/profile") + @ApiOperation(value = "고유 아이디에 해당하는 유저 프로필 정보를 가져온다 (AccessToken)") + public CommonApiResponse getBasicProfileById( + @PathVariable("id") Long id, + @ApiIgnore @AuthMember Member member + ) { + return CommonApiResponse.of(matchService.getBasicProfileById(member, id)); + } + + @GetMapping("/{memberId}/profile/open") + @ApiOperation(value = "번호 오픈을 사용한 고유 아이디 유저의 프로필 정보를 가져온다 (AccessToken)") + public CommonApiResponse getOpenProfileById( + @PathVariable("memberId") Long id, + @ApiIgnore @AuthMember Member member + ) { + return CommonApiResponse.of(matchService.getOpenProfileById(member, id)); + } + @PostMapping("/{id}/accept") @ApiOperation(value = "현재 호감을 보낸 상대를 수락하여 매칭을 성사시킨다 (AccessToken)") public CommonApiResponse accept( - @PathVariable("id") Long id, + @PathVariable("memberId") Long id, @ApiIgnore @AuthMember Member member ) { return CommonApiResponse.of(matchService.accept(member, id)); diff --git a/src/main/java/com/tikitaka/naechinso/domain/match/MatchRepository.java b/src/main/java/com/tikitaka/naechinso/domain/match/MatchRepository.java index c5626db..551b2f1 100644 --- a/src/main/java/com/tikitaka/naechinso/domain/match/MatchRepository.java +++ b/src/main/java/com/tikitaka/naechinso/domain/match/MatchRepository.java @@ -49,6 +49,19 @@ public interface MatchRepository extends JpaRepository { "AND m.status = com.tikitaka.naechinso.domain.match.constant.MatchStatus.ACCEPTED") Optional findAllByIdAndMemberAndStatusIsAccept(Long id, Member member); + @Query("SELECT CASE WHEN COUNT(m) > 0 THEN 'true' ELSE 'false' END " + + "FROM Match m " + + "JOIN m.fromMember f JOIN m.toMember t " + + "WHERE f.id = :id OR t.id = :id") + Boolean existsByTargetId(Long id); + + @Query("SELECT CASE WHEN COUNT(m) > 0 THEN 'true' ELSE 'false' END " + + "FROM Match m " + + "JOIN m.fromMember f JOIN m.toMember t " + + "WHERE (f.id = :id OR t.id = :id) " + + "AND m.status = com.tikitaka.naechinso.domain.match.constant.MatchStatus.OPEN") + Boolean existsByTargetIdAndStatusIsOpen(Long id); + Optional findByIdAndToMemberAndStatus(Long id, Member member, MatchStatus status); Optional findByIdAndStatus(Long id, MatchStatus status); diff --git a/src/main/java/com/tikitaka/naechinso/domain/match/MatchService.java b/src/main/java/com/tikitaka/naechinso/domain/match/MatchService.java index bf3b39e..4aeaf0e 100644 --- a/src/main/java/com/tikitaka/naechinso/domain/match/MatchService.java +++ b/src/main/java/com/tikitaka/naechinso/domain/match/MatchService.java @@ -1,18 +1,14 @@ package com.tikitaka.naechinso.domain.match; import com.tikitaka.naechinso.domain.card.CardRepository; -import com.tikitaka.naechinso.domain.card.CardService; +import com.tikitaka.naechinso.domain.card.dto.CardOppositeMemberProfileResponseDTO; import com.tikitaka.naechinso.domain.card.entity.Card; import com.tikitaka.naechinso.domain.match.constant.MatchStatus; -import com.tikitaka.naechinso.domain.match.dto.MatchListResponseDTO; -import com.tikitaka.naechinso.domain.match.dto.MatchResponseDTO; -import com.tikitaka.naechinso.domain.match.dto.MatchThumbnailResponseDTO; +import com.tikitaka.naechinso.domain.match.dto.*; import com.tikitaka.naechinso.domain.match.entity.Match; import com.tikitaka.naechinso.domain.member.MemberRepository; -import com.tikitaka.naechinso.domain.member.MemberService; import com.tikitaka.naechinso.domain.member.entity.Member; import com.tikitaka.naechinso.global.error.ErrorCode; -import com.tikitaka.naechinso.global.error.exception.BadRequestException; import com.tikitaka.naechinso.global.error.exception.ForbiddenException; import com.tikitaka.naechinso.global.error.exception.NotFoundException; import lombok.RequiredArgsConstructor; @@ -21,7 +17,6 @@ import org.springframework.transaction.annotation.Transactional; import java.util.List; -import java.util.Optional; import java.util.stream.Collectors; @Slf4j @@ -132,6 +127,36 @@ public List findAllByMatchComplete(Member authMember) } + /** + * 호감 주거나 받은 상대의 프로필 정보를 가져옴 + * */ + public MatchBasicProfileResponseDTO getBasicProfileById(Member authMember, Long id) { + //관련 매칭 정보가 없으면 403 + if(!matchRepository.existsByTargetId(id)){ + throw new ForbiddenException(ErrorCode.FORBIDDEN_PROFILE); + } + + Member oppositeMember = memberRepository.findByMember(authMember) + .orElseThrow(() -> new NotFoundException(ErrorCode.USER_NOT_FOUND)); + + return MatchBasicProfileResponseDTO.of(oppositeMember); + } + + /** + * 호감 주거나 받은 상대의 프로필 정보를 가져옴 + * */ + public MatchOpenProfileResponseDTO getOpenProfileById(Member authMember, Long id) { + //OPEN 상태인 매칭 정보가 없다면 에러 + if(!matchRepository.existsByTargetIdAndStatusIsOpen(id)){ + throw new ForbiddenException(ErrorCode.FORBIDDEN_PROFILE); + } + + Member oppositeMember = memberRepository.findByMember(authMember) + .orElseThrow(() -> new NotFoundException(ErrorCode.USER_NOT_FOUND)); + + return MatchOpenProfileResponseDTO.of(oppositeMember); + } + public MatchListResponseDTO findAllByMember(Member authMember) { return MatchListResponseDTO.of(authMember); } diff --git a/src/main/java/com/tikitaka/naechinso/domain/match/dto/MatchBasicProfileResponseDTO.java b/src/main/java/com/tikitaka/naechinso/domain/match/dto/MatchBasicProfileResponseDTO.java new file mode 100644 index 0000000..aa8186b --- /dev/null +++ b/src/main/java/com/tikitaka/naechinso/domain/match/dto/MatchBasicProfileResponseDTO.java @@ -0,0 +1,134 @@ +package com.tikitaka.naechinso.domain.match.dto; + +import com.tikitaka.naechinso.domain.member.constant.Gender; +import com.tikitaka.naechinso.domain.member.entity.Member; +import com.tikitaka.naechinso.domain.member.entity.MemberDetail; +import com.tikitaka.naechinso.domain.recommend.entity.Recommend; +import com.tikitaka.naechinso.global.error.ErrorCode; +import com.tikitaka.naechinso.global.error.exception.InternalServerException; +import com.tikitaka.naechinso.global.error.exception.NotFoundException; +import com.tikitaka.naechinso.global.util.CustomStringUtil; +import lombok.*; + +import java.util.List; + +/** + * 매칭된 상대의 휴대전화를 포함한 프로필을 반환하는 DTO 입니다 + * @author gengminy 221013 + * */ +@AllArgsConstructor +@NoArgsConstructor +@Getter +@Builder +@ToString +public class MatchBasicProfileResponseDTO { + private List images; + private String name; + private int age; + private String address; + private Gender gender; + + private String jobName; + private String jobPart; + private String jobLocation; + + private String eduName; + private String eduMajor; + private String eduLevel; + + private String personality; + private String religion; + private int height; + private String smoke; + private String drink; + + private String hobby; + private String style; + private String introduce; + + private String mbti; + private Recommendation recommend; + + @AllArgsConstructor + @NoArgsConstructor + @Getter + @Builder + @ToString + public static class Recommendation { + private String name; + private Gender gender; + private String appeal; + + private String jobName; + private String jobPart; + private String jobLocation; + private String eduName; + private String eduMajor; + private String eduLevel; + + private String meet; + private String period; + private String appealDetail; + } + + public static MatchBasicProfileResponseDTO of(Member targetMember) { + MemberDetail detail = targetMember.getDetail(); + //디테일 없는 유저로 시도 + if (detail == null) { + throw new NotFoundException(ErrorCode.USER_NOT_SIGNED_UP); + } + + //추천받은 적 없는 유저를 가져오는 것을 시도 + if (targetMember.getRecommendReceived() == null){ + throw new NotFoundException(ErrorCode.RECOMMEND_NOT_FOUND); + } + + try { + for (Recommend recommend : targetMember.getRecommendReceived()) { + //추천 상태 검증 + if (recommend.getSender() != null && recommend.getReceiver() != null) { + return MatchBasicProfileResponseDTO.builder() + .images(detail.getImages()) + .name(CustomStringUtil.hideName(targetMember.getName())) + .age(targetMember.getAge()) + .address(detail.getAddress()) + .jobName(targetMember.getJobName()) + .jobPart(targetMember.getJobPart()) + .jobLocation(targetMember.getJobLocation()) + .eduName(targetMember.getEduName()) + .eduMajor(targetMember.getEduMajor()) + .eduLevel(targetMember.getEduLevel()) + .gender(targetMember.getGender()) + .personality(detail.getPersonality()) + .religion(detail.getReligion()) + .height(detail.getHeight()) + .smoke(detail.getSmoke()) + .drink(detail.getDrink()) + .hobby(detail.getHobby()) + .style(detail.getStyle()) + .introduce(detail.getIntroduce()) + .mbti(detail.getMbti()) + .recommend(Recommendation.builder() + .name(CustomStringUtil.hideName(recommend.getSenderName())) + .gender(recommend.getSenderGender()) + .appeal(recommend.getReceiverAppeal()) + .appealDetail(recommend.getReceiverAppealDetail()) + .eduName(recommend.getSender().getEduName()) + .eduMajor(recommend.getSender().getEduMajor()) + .eduLevel(recommend.getSender().getEduLevel()) + .jobName(recommend.getSender().getJobName()) + .jobPart(recommend.getSender().getJobPart()) + .jobLocation(recommend.getSender().getJobLocation()) + .meet(recommend.getReceiverMeet()) + .period(recommend.getReceiverPeriod()) + .build()) + .build(); + + } + } + } catch (Exception e) { + throw new InternalServerException(ErrorCode._INTERNAL_SERVER_ERROR); + } + throw new NotFoundException(ErrorCode.RECOMMEND_NOT_FOUND); + } +} diff --git a/src/main/java/com/tikitaka/naechinso/domain/match/dto/MatchOppositeProfileResponseDTO.java b/src/main/java/com/tikitaka/naechinso/domain/match/dto/MatchOpenProfileResponseDTO.java similarity index 96% rename from src/main/java/com/tikitaka/naechinso/domain/match/dto/MatchOppositeProfileResponseDTO.java rename to src/main/java/com/tikitaka/naechinso/domain/match/dto/MatchOpenProfileResponseDTO.java index 577169a..2d23c11 100644 --- a/src/main/java/com/tikitaka/naechinso/domain/match/dto/MatchOppositeProfileResponseDTO.java +++ b/src/main/java/com/tikitaka/naechinso/domain/match/dto/MatchOpenProfileResponseDTO.java @@ -21,7 +21,7 @@ @Getter @Builder @ToString -public class MatchOppositeProfileResponseDTO { +public class MatchOpenProfileResponseDTO { private List images; private String name; private int age; @@ -73,7 +73,7 @@ public static class Recommendation { private String appealDetail; } - public static MatchOppositeProfileResponseDTO of(Member targetMember) { + public static MatchOpenProfileResponseDTO of(Member targetMember) { MemberDetail detail = targetMember.getDetail(); //디테일 없는 유저로 시도 if (detail == null) { @@ -89,7 +89,7 @@ public static MatchOppositeProfileResponseDTO of(Member targetMember) { for (Recommend recommend : targetMember.getRecommendReceived()) { //추천 상태 검증 if (recommend.getSender() != null && recommend.getReceiver() != null) { - return MatchOppositeProfileResponseDTO.builder() + return MatchOpenProfileResponseDTO.builder() .images(detail.getImages()) .name(targetMember.getName()) .phone(targetMember.getPhone()) diff --git a/src/main/java/com/tikitaka/naechinso/domain/member/MemberController.java b/src/main/java/com/tikitaka/naechinso/domain/member/MemberController.java index 6757ea0..364303b 100644 --- a/src/main/java/com/tikitaka/naechinso/domain/member/MemberController.java +++ b/src/main/java/com/tikitaka/naechinso/domain/member/MemberController.java @@ -44,14 +44,15 @@ public CommonApiResponse getMemberById( return CommonApiResponse.of(MemberCommonResponseDTO.of(memberService.findById(id))); } - @GetMapping("/{id}/profile") - @ApiOperation(value = "고유 아이디의 유저 프로필과 추천인 정보를 가져온다 (AccessToken)") - public CommonApiResponse getMemberProfileById( - @PathVariable("id") Long id, - @ApiIgnore @AuthMember Member member - ) { - return CommonApiResponse.of(memberService.readOppositeMemberDetailAndRecommendById(member, id)); - } +// @GetMapping("/{id}/profile") +// @ApiOperation(value = "고유 아이디의 유저 프로필과 추천인 정보를 가져온다 (AccessToken)") +// public CommonApiResponse getMemberProfileById( +// @PathVariable("id") Long id, +// @ApiIgnore @AuthMember Member member +// ) { +// return CommonApiResponse.of(memberService.readOppositeMemberDetailAndRecommendById(member, id)); +// } + @GetMapping("/detail") @ApiOperation(value = "회원가입 세부 정보를 가져온다 (AccessToken)") public CommonApiResponse getMemberDetail( diff --git a/src/main/java/com/tikitaka/naechinso/domain/member/MemberService.java b/src/main/java/com/tikitaka/naechinso/domain/member/MemberService.java index d08ead4..d7f77c9 100644 --- a/src/main/java/com/tikitaka/naechinso/domain/member/MemberService.java +++ b/src/main/java/com/tikitaka/naechinso/domain/member/MemberService.java @@ -92,21 +92,21 @@ public MemberDetailResponseDTO readDetail(Member member) { } - /** - * 랜덤 추천받은 상대의 프로필 카드를 가져오는 서비스 로직 - * ACTIVE 한 카드에만 접근 권한이 있음 - * */ - public MemberOppositeProfileResponseDTO readOppositeMemberDetailAndRecommendById(Member authMember, Long id) { - //현재 ACTIVE 한 카드와 요청 id가 같지 않으면 에러 - Card activeCard = cardService.findByMemberAndIsActiveTrue(authMember); - Long targetId = activeCard.getTargetMemberId(); - if (!targetId.equals(id)) { - throw new ForbiddenException(ErrorCode.FORBIDDEN_PROFILE); - } - - Member oppositeMember = findById(targetId); - return MemberOppositeProfileResponseDTO.of(oppositeMember); - } +// /** +// * 랜덤 추천받은 상대의 프로필 카드를 가져오는 서비스 로직 +// * ACTIVE 한 카드에만 접근 권한이 있음 +// * */ +// public MemberOppositeProfileResponseDTO readOppositeMemberDetailAndRecommendById(Member authMember, Long id) { +// //현재 ACTIVE 한 카드와 요청 id가 같지 않으면 에러 +// Card activeCard = cardService.findByMemberAndIsActiveTrue(authMember); +// Long targetId = activeCard.getTargetMemberId(); +// if (!targetId.equals(id)) { +// throw new ForbiddenException(ErrorCode.FORBIDDEN_PROFILE); +// } +// +// Member oppositeMember = findById(targetId); +// return MemberOppositeProfileResponseDTO.of(oppositeMember); +// } public MemberDetailResponseDTO createDetail(Member authMember, MemberDetailJoinRequestDTO dto) { //영속성 유지를 위한 fetch From c87734cf6666ac87ce5fa6fd2ddd8e5ba424c3ba Mon Sep 17 00:00:00 2001 From: gengminy Date: Wed, 26 Oct 2022 20:56:50 +0900 Subject: [PATCH 40/72] =?UTF-8?q?:rocket:=20feat(match):=20=EB=82=A8?= =?UTF-8?q?=EC=9D=80=20=EC=B6=94=EC=B2=9C=20=ED=9A=9F=EC=88=98=20=EB=B0=98?= =?UTF-8?q?=ED=99=98=20=EA=B5=AC=ED=98=84=20#45?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../naechinso/domain/TestController.java | 6 +---- .../naechinso/domain/card/CardController.java | 13 ++++++++-- .../naechinso/domain/card/CardService.java | 25 +++++++++++++++++++ .../domain/card/dto/CardCountResponseDTO.java | 11 ++++++++ 4 files changed, 48 insertions(+), 7 deletions(-) create mode 100644 src/main/java/com/tikitaka/naechinso/domain/card/dto/CardCountResponseDTO.java diff --git a/src/main/java/com/tikitaka/naechinso/domain/TestController.java b/src/main/java/com/tikitaka/naechinso/domain/TestController.java index da967ed..53e6550 100644 --- a/src/main/java/com/tikitaka/naechinso/domain/TestController.java +++ b/src/main/java/com/tikitaka/naechinso/domain/TestController.java @@ -233,12 +233,9 @@ public CommonApiResponse createJobPendingMemberAndRecommendOther( } @GetMapping("/create-two-detail-user") - @ApiOperation(value = "[*TEST*] 멤버 DB를 초기화한 후, 정회원으로 가입한 유저를 둘 생성하고 그 중 첫 번째 유저의 엑세스 토큰을 반환한다") + @ApiOperation(value = "[*TEST*] 정회원으로 가입한 유저를 둘 생성하고 그 중 첫 번째 유저의 엑세스 토큰을 반환한다") public CommonApiResponse createTwoRegularMember() { - memberRepository.deleteAll(); - recommendRepository.deleteAll(); - MemberCommonJoinResponseDTO senderDTO = memberService.joinCommonMember( "01012345678", MemberCommonJoinRequestDTO.builder() @@ -458,7 +455,6 @@ public CommonApiResponse createMultipleMembers() { .build() ); - accessToken = senderDTO.getAccessToken(); } return CommonApiResponse.of(accessToken); diff --git a/src/main/java/com/tikitaka/naechinso/domain/card/CardController.java b/src/main/java/com/tikitaka/naechinso/domain/card/CardController.java index a2d8dbd..fcdca2c 100644 --- a/src/main/java/com/tikitaka/naechinso/domain/card/CardController.java +++ b/src/main/java/com/tikitaka/naechinso/domain/card/CardController.java @@ -1,5 +1,6 @@ package com.tikitaka.naechinso.domain.card; +import com.tikitaka.naechinso.domain.card.dto.CardCountResponseDTO; import com.tikitaka.naechinso.domain.card.dto.CardOppositeMemberProfileResponseDTO; import com.tikitaka.naechinso.domain.card.dto.CardResponseDTO; import com.tikitaka.naechinso.domain.card.dto.CardThumbnailResponseDTO; @@ -26,7 +27,7 @@ public class CardController { public CommonApiResponse> getAllCardsByMember( @ApiIgnore @AuthMember Member member ) { - return CommonApiResponse.of(cardService.findAllDTOByMember(member)); + return CommonApiResponse.of(cardService.findAllCard(member)); } @GetMapping("/find") @@ -37,6 +38,14 @@ public CommonApiResponse> getAllCards( return CommonApiResponse.of(cardService.findAllDTO()); } + @GetMapping("/count") + @ApiOperation(value = "오늘의 남은 추천 횟수를 반환한다 (AccessToken)") + public CommonApiResponse getRemainingCount( + @ApiIgnore @AuthMember Member member + ) { + return CommonApiResponse.of(cardService.getRemainingCount(member)); + } + @GetMapping("/{id}/profile") @ApiOperation(value = "고유 아이디의 유저 프로필과 추천인 정보를 가져온다 (AccessToken)") public CommonApiResponse getProfileByCardMember( @@ -47,7 +56,7 @@ public CommonApiResponse getProfileByCardM } @PostMapping - @ApiOperation(value = "새로운 카드를 하나 생성한다 (AccessToken)") + @ApiOperation(value = "새로운 추천을 받는다 (AccessToken)") public CommonApiResponse createCardByMember( @ApiIgnore @AuthMember Member member ) { diff --git a/src/main/java/com/tikitaka/naechinso/domain/card/CardService.java b/src/main/java/com/tikitaka/naechinso/domain/card/CardService.java index 5829585..0a23a57 100644 --- a/src/main/java/com/tikitaka/naechinso/domain/card/CardService.java +++ b/src/main/java/com/tikitaka/naechinso/domain/card/CardService.java @@ -1,5 +1,6 @@ package com.tikitaka.naechinso.domain.card; +import com.tikitaka.naechinso.domain.card.dto.CardCountResponseDTO; import com.tikitaka.naechinso.domain.card.dto.CardOppositeMemberProfileResponseDTO; import com.tikitaka.naechinso.domain.card.dto.CardResponseDTO; import com.tikitaka.naechinso.domain.card.dto.CardThumbnailResponseDTO; @@ -13,12 +14,16 @@ import com.tikitaka.naechinso.global.error.exception.NotFoundException; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; +import org.springframework.http.ResponseEntity; import org.springframework.stereotype.Service; +import org.springframework.web.bind.annotation.ResponseBody; import java.time.LocalDate; import java.time.LocalDateTime; import java.time.LocalTime; +import java.util.HashMap; import java.util.List; +import java.util.Map; import java.util.Random; import java.util.stream.Collectors; @@ -30,6 +35,26 @@ public class CardService { private final CardRepository cardRepository; private final MemberRepository memberRepository; + + /** + * 내가 받았던 모든 카드 기록을 가져온다 (챗봇 썸네일) + */ + public List findAllCard(Member authMember){ + return cardRepository.findAllDTOByMember(authMember); + } + + /** + * 내가 받았던 모든 카드 기록을 가져온다 (챗봇 썸네일) + */ + public CardCountResponseDTO getRemainingCount(Member authMember) { + long count = 3L - countCardByMemberAndCreatedAtBetween(authMember); + if (count < 0) { + return new CardCountResponseDTO(0L); + } + else return new CardCountResponseDTO(count); + } + + /** * 추천 받았던 유저를 필터링한 랜덤 추천 카드를 만든다 * */ diff --git a/src/main/java/com/tikitaka/naechinso/domain/card/dto/CardCountResponseDTO.java b/src/main/java/com/tikitaka/naechinso/domain/card/dto/CardCountResponseDTO.java new file mode 100644 index 0000000..6f77360 --- /dev/null +++ b/src/main/java/com/tikitaka/naechinso/domain/card/dto/CardCountResponseDTO.java @@ -0,0 +1,11 @@ +package com.tikitaka.naechinso.domain.card.dto; + +import lombok.*; + +@AllArgsConstructor +@NoArgsConstructor +@Getter +@ToString +public class CardCountResponseDTO { + long count; +} From d9e67079b5c16fdfdbfbb7176ec7760909c3cc0f Mon Sep 17 00:00:00 2001 From: gengminy Date: Wed, 26 Oct 2022 22:10:25 +0900 Subject: [PATCH 41/72] =?UTF-8?q?:hammer:=20fix(match):=20=EB=A7=A4?= =?UTF-8?q?=EC=B9=AD=20=EA=B3=B5=ED=86=B5=20DTO=20=ED=95=84=EB=93=9C=20?= =?UTF-8?q?=EC=88=98=EC=A0=95=20#45?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../naechinso/domain/TestController.java | 1 + .../naechinso/domain/card/CardController.java | 9 ++++----- .../naechinso/domain/card/CardService.java | 8 ++------ .../card/dto/CardThumbnailResponseDTO.java | 11 ++-------- .../tikitaka/naechinso/domain/card/todo.md | 12 ----------- .../domain/match/MatchController.java | 4 ++-- .../domain/match/dto/MatchResponseDTO.java | 20 ++----------------- .../naechinso/global/util/DateUtil.java | 16 +++++++++++++++ 8 files changed, 29 insertions(+), 52 deletions(-) delete mode 100644 src/main/java/com/tikitaka/naechinso/domain/card/todo.md create mode 100644 src/main/java/com/tikitaka/naechinso/global/util/DateUtil.java diff --git a/src/main/java/com/tikitaka/naechinso/domain/TestController.java b/src/main/java/com/tikitaka/naechinso/domain/TestController.java index 53e6550..9d87fc2 100644 --- a/src/main/java/com/tikitaka/naechinso/domain/TestController.java +++ b/src/main/java/com/tikitaka/naechinso/domain/TestController.java @@ -479,6 +479,7 @@ public CommonApiResponse dropAllTable( @DeleteMapping("/drop-all-table") @ApiOperation(value = "[*TEST*] 모든 DB 테이블을 초기화") public CommonApiResponse dropAllTable(){ + matchRepository.deleteAll(); recommendRepository.deleteAll(); cardRepository.deleteAll(); memberDetailRepository.deleteAll(); diff --git a/src/main/java/com/tikitaka/naechinso/domain/card/CardController.java b/src/main/java/com/tikitaka/naechinso/domain/card/CardController.java index fcdca2c..bcc6d7f 100644 --- a/src/main/java/com/tikitaka/naechinso/domain/card/CardController.java +++ b/src/main/java/com/tikitaka/naechinso/domain/card/CardController.java @@ -46,13 +46,12 @@ public CommonApiResponse getRemainingCount( return CommonApiResponse.of(cardService.getRemainingCount(member)); } - @GetMapping("/{id}/profile") - @ApiOperation(value = "고유 아이디의 유저 프로필과 추천인 정보를 가져온다 (AccessToken)") - public CommonApiResponse getProfileByCardMember( - @PathVariable("id") Long id, + @GetMapping("/profile") + @ApiOperation(value = "현재 활성화된 카드의 상대 프로필과 추천인 정보를 가져온다 (AccessToken)") + public CommonApiResponse getProfileByCard( @ApiIgnore @AuthMember Member member ) { - return CommonApiResponse.of(cardService.findOppositeMemberDetailAndRecommendById(member, id)); + return CommonApiResponse.of(cardService.getCardProfileById(member)); } @PostMapping diff --git a/src/main/java/com/tikitaka/naechinso/domain/card/CardService.java b/src/main/java/com/tikitaka/naechinso/domain/card/CardService.java index 0a23a57..9f35d48 100644 --- a/src/main/java/com/tikitaka/naechinso/domain/card/CardService.java +++ b/src/main/java/com/tikitaka/naechinso/domain/card/CardService.java @@ -111,15 +111,11 @@ public CardResponseDTO rejectCard(Member authMember) { * 랜덤 추천받은 상대의 프로필 카드를 가져오는 서비스 로직 * ACTIVE 한 카드에만 접근 권한이 있음 * */ - public CardOppositeMemberProfileResponseDTO findOppositeMemberDetailAndRecommendById(Member authMember, Long id) { - //현재 ACTIVE 한 카드와 요청 id가 같지 않으면 에러 + public CardOppositeMemberProfileResponseDTO getCardProfileById(Member authMember) { Card activeCard = findByMemberAndIsActiveTrue(authMember); Long targetId = activeCard.getTargetMemberId(); - if (!targetId.equals(id)) { - throw new ForbiddenException(ErrorCode.FORBIDDEN_PROFILE); - } - Member oppositeMember = memberRepository.findByMember(authMember) + Member oppositeMember = memberRepository.findById(targetId) .orElseThrow(() -> new NotFoundException(ErrorCode.USER_NOT_FOUND)); return CardOppositeMemberProfileResponseDTO.of(oppositeMember); } diff --git a/src/main/java/com/tikitaka/naechinso/domain/card/dto/CardThumbnailResponseDTO.java b/src/main/java/com/tikitaka/naechinso/domain/card/dto/CardThumbnailResponseDTO.java index e059cdb..ae66bbe 100644 --- a/src/main/java/com/tikitaka/naechinso/domain/card/dto/CardThumbnailResponseDTO.java +++ b/src/main/java/com/tikitaka/naechinso/domain/card/dto/CardThumbnailResponseDTO.java @@ -7,6 +7,7 @@ import com.tikitaka.naechinso.domain.recommend.entity.Recommend; import com.tikitaka.naechinso.global.error.ErrorCode; import com.tikitaka.naechinso.global.error.exception.NotFoundException; +import com.tikitaka.naechinso.global.util.DateUtil; import lombok.*; import java.time.*; @@ -76,7 +77,7 @@ public static CardThumbnailResponseDTO of(Card card, Member targetMember) { .targetMemberId(card.getTargetMemberId()) .isActive(card.getIsActive()) .createdAt(card.getCreatedAt().toString()) - .dueDate(generateDueDate(card.getCreatedAt())) + .dueDate(DateUtil.getDueDay(card.getCreatedAt(), 7L)) .images(targetMember.getDetail().getImages()) .name(dto.getName()) .age(dto.getAge()) @@ -105,12 +106,4 @@ public static CardThumbnailResponseDTO of(Card card, Member targetMember) { .build(); } - private static long generateDueDate(LocalDateTime createdAt) { - LocalDateTime endDatetime = LocalDateTime.of(createdAt.toLocalDate().plusDays(7), LocalTime.of(23,59,59)); - long dueDate = Duration.between(LocalDateTime.now(), endDatetime).toDays(); - if (dueDate < 0) { - return 0; - } - return dueDate; - } } diff --git a/src/main/java/com/tikitaka/naechinso/domain/card/todo.md b/src/main/java/com/tikitaka/naechinso/domain/card/todo.md deleted file mode 100644 index 544f9d3..0000000 --- a/src/main/java/com/tikitaka/naechinso/domain/card/todo.md +++ /dev/null @@ -1,12 +0,0 @@ -# TODO - -매칭과는 별개로 채팅창에서 -랜덤 상대를 추천해주는 것에 대해 구현해야함 - -랜덤 카드 추천은 하루에 세 개 - -둘 중 한명이 호감을 보내면 매칭 내역으로 보냄 - -만약 이미 유효한 매칭 내역에 있는 상대라면 번호 오픈 - -매칭 상태에서 한명만 결제를 해도 번호 오픈 \ No newline at end of file diff --git a/src/main/java/com/tikitaka/naechinso/domain/match/MatchController.java b/src/main/java/com/tikitaka/naechinso/domain/match/MatchController.java index 8d7573c..3123a0e 100644 --- a/src/main/java/com/tikitaka/naechinso/domain/match/MatchController.java +++ b/src/main/java/com/tikitaka/naechinso/domain/match/MatchController.java @@ -58,7 +58,7 @@ public CommonApiResponse like( @GetMapping("/{memberId}/profile") @ApiOperation(value = "고유 아이디에 해당하는 유저 프로필 정보를 가져온다 (AccessToken)") public CommonApiResponse getBasicProfileById( - @PathVariable("id") Long id, + @PathVariable("memberId") Long id, @ApiIgnore @AuthMember Member member ) { return CommonApiResponse.of(matchService.getBasicProfileById(member, id)); @@ -76,7 +76,7 @@ public CommonApiResponse getOpenProfileById( @PostMapping("/{id}/accept") @ApiOperation(value = "현재 호감을 보낸 상대를 수락하여 매칭을 성사시킨다 (AccessToken)") public CommonApiResponse accept( - @PathVariable("memberId") Long id, + @PathVariable("id") Long id, @ApiIgnore @AuthMember Member member ) { return CommonApiResponse.of(matchService.accept(member, id)); diff --git a/src/main/java/com/tikitaka/naechinso/domain/match/dto/MatchResponseDTO.java b/src/main/java/com/tikitaka/naechinso/domain/match/dto/MatchResponseDTO.java index 3bf93b6..23d0fe8 100644 --- a/src/main/java/com/tikitaka/naechinso/domain/match/dto/MatchResponseDTO.java +++ b/src/main/java/com/tikitaka/naechinso/domain/match/dto/MatchResponseDTO.java @@ -21,14 +21,7 @@ public class MatchResponseDTO { private MatchStatus status; - private String phone; - private Long fromMemberId; - - private Long toMemberId; - - private String createdAt; - - private String dueDate; + private Long targetMemberId; public static MatchResponseDTO of(Match match) { if (match.getFromMember() == null || match.getToMember() == null) { @@ -37,16 +30,7 @@ public static MatchResponseDTO of(Match match) { return MatchResponseDTO.builder() .id(match.getId()) .status(match.getStatus()) - .fromMemberId(match.getFromMember().getId()) - .toMemberId(match.getToMember().getId()) - .createdAt(match.getCreatedAt().toString()) + .targetMemberId(match.getToMember().getId()) .build(); } - - public MatchResponseDTO(Match match) { - if (match.getFromMember() == null || match.getToMember() == null) { - throw new NotFoundException(ErrorCode.USER_NOT_FOUND); - } - this.fromMemberId = match.getFromMember().getId(); - } } diff --git a/src/main/java/com/tikitaka/naechinso/global/util/DateUtil.java b/src/main/java/com/tikitaka/naechinso/global/util/DateUtil.java new file mode 100644 index 0000000..cd048dd --- /dev/null +++ b/src/main/java/com/tikitaka/naechinso/global/util/DateUtil.java @@ -0,0 +1,16 @@ +package com.tikitaka.naechinso.global.util; + +import java.time.Duration; +import java.time.LocalDateTime; +import java.time.LocalTime; + +public class DateUtil { + public static long getDueDay(LocalDateTime createdAt, long addDay) { + LocalDateTime endDatetime = LocalDateTime.of(createdAt.toLocalDate().plusDays(addDay), LocalTime.of(23,59,59)); + long dueDay = Duration.between(LocalDateTime.now(), endDatetime).toDays(); + if (dueDay < 0) { + return 0; + } + return dueDay; + } +} From bbd0a1c791089625013eb80ef4363702daaa122d Mon Sep 17 00:00:00 2001 From: gengminy Date: Wed, 26 Oct 2022 23:02:27 +0900 Subject: [PATCH 42/72] =?UTF-8?q?:rocket:=20feat(point):=20=ED=8F=AC?= =?UTF-8?q?=EC=9D=B8=ED=8A=B8=20=EC=97=94=ED=8B=B0=ED=8B=B0=20=EC=A0=95?= =?UTF-8?q?=EC=9D=98=20#48?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../domain/member/MemberDetailRepository.java | 1 - .../domain/member/MemberRepository.java | 1 - .../domain/point/PointController.java | 34 ++++++++++++++++++- .../domain/point/PointRepository.java | 12 ++++++- .../naechinso/domain/point/PointService.java | 34 +++++++++++++++++++ .../domain/point/constant/PointType.java | 25 ++++++++++++++ .../point/dto/PointChargeRequestDTO.java | 17 ++++++++++ .../domain/point/dto/PointResponseDTO.java | 26 ++++++++++++++ .../naechinso/domain/point/entity/Point.java | 6 ++-- .../domain/recommend/RecommendRepository.java | 1 - .../recommend/dto/RecommendResponseDTO.java | 3 ++ 11 files changed, 153 insertions(+), 7 deletions(-) create mode 100644 src/main/java/com/tikitaka/naechinso/domain/point/constant/PointType.java create mode 100644 src/main/java/com/tikitaka/naechinso/domain/point/dto/PointChargeRequestDTO.java create mode 100644 src/main/java/com/tikitaka/naechinso/domain/point/dto/PointResponseDTO.java diff --git a/src/main/java/com/tikitaka/naechinso/domain/member/MemberDetailRepository.java b/src/main/java/com/tikitaka/naechinso/domain/member/MemberDetailRepository.java index dca741d..37e52c8 100644 --- a/src/main/java/com/tikitaka/naechinso/domain/member/MemberDetailRepository.java +++ b/src/main/java/com/tikitaka/naechinso/domain/member/MemberDetailRepository.java @@ -4,6 +4,5 @@ import org.springframework.data.jpa.repository.JpaRepository; import org.springframework.stereotype.Repository; -@Repository public interface MemberDetailRepository extends JpaRepository { } diff --git a/src/main/java/com/tikitaka/naechinso/domain/member/MemberRepository.java b/src/main/java/com/tikitaka/naechinso/domain/member/MemberRepository.java index ec54b45..c708974 100644 --- a/src/main/java/com/tikitaka/naechinso/domain/member/MemberRepository.java +++ b/src/main/java/com/tikitaka/naechinso/domain/member/MemberRepository.java @@ -12,7 +12,6 @@ import java.util.List; import java.util.Optional; -@Repository public interface MemberRepository extends JpaRepository { Optional findByPhone(String phone); diff --git a/src/main/java/com/tikitaka/naechinso/domain/point/PointController.java b/src/main/java/com/tikitaka/naechinso/domain/point/PointController.java index e7372d3..b61c655 100644 --- a/src/main/java/com/tikitaka/naechinso/domain/point/PointController.java +++ b/src/main/java/com/tikitaka/naechinso/domain/point/PointController.java @@ -1,7 +1,39 @@ package com.tikitaka.naechinso.domain.point; +import com.tikitaka.naechinso.domain.member.dto.MemberCommonResponseDTO; +import com.tikitaka.naechinso.domain.member.entity.Member; +import com.tikitaka.naechinso.domain.point.dto.PointChargeRequestDTO; +import com.tikitaka.naechinso.domain.point.dto.PointResponseDTO; +import com.tikitaka.naechinso.global.annotation.AuthMember; +import com.tikitaka.naechinso.global.config.CommonApiResponse; +import io.swagger.annotations.ApiOperation; +import lombok.extern.slf4j.Slf4j; import org.springframework.stereotype.Controller; +import org.springframework.web.bind.annotation.*; +import springfox.documentation.annotations.ApiIgnore; -@Controller +@Slf4j +@RestController +@RequestMapping("/point") public class PointController { + + private PointService pointService; + + @GetMapping + @ApiOperation(value = "유저 자신의 포인트 충전 / 사용 내역을 모두 가져온다 (AccessToken)") + public CommonApiResponse getPointHistory( + @ApiIgnore @AuthMember Member member + ) { +// return CommonApiResponse.of(pointService.readCommonMember(member)); + return null; + } + + @PostMapping("/charge") + @ApiOperation(value = "유저 자신의 모든 정보를 가져온다 (AccessToken)") + public CommonApiResponse getMyInformation( + @ApiIgnore @AuthMember Member member, + @RequestBody PointChargeRequestDTO requestDTO + ) { + return CommonApiResponse.of(pointService.charge(member, requestDTO)); + } } diff --git a/src/main/java/com/tikitaka/naechinso/domain/point/PointRepository.java b/src/main/java/com/tikitaka/naechinso/domain/point/PointRepository.java index 55501bf..8af69ea 100644 --- a/src/main/java/com/tikitaka/naechinso/domain/point/PointRepository.java +++ b/src/main/java/com/tikitaka/naechinso/domain/point/PointRepository.java @@ -1,4 +1,14 @@ package com.tikitaka.naechinso.domain.point; -public interface PointRepository { +import com.tikitaka.naechinso.domain.member.entity.Member; +import com.tikitaka.naechinso.domain.point.constant.PointType; +import com.tikitaka.naechinso.domain.point.entity.Point; +import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.data.jpa.repository.Query; + +import java.util.List; + +public interface PointRepository extends JpaRepository { + + List findAllByMember(Member member); } diff --git a/src/main/java/com/tikitaka/naechinso/domain/point/PointService.java b/src/main/java/com/tikitaka/naechinso/domain/point/PointService.java index 0f65b5b..49fb967 100644 --- a/src/main/java/com/tikitaka/naechinso/domain/point/PointService.java +++ b/src/main/java/com/tikitaka/naechinso/domain/point/PointService.java @@ -1,7 +1,41 @@ package com.tikitaka.naechinso.domain.point; +import com.tikitaka.naechinso.domain.member.MemberRepository; +import com.tikitaka.naechinso.domain.member.entity.Member; +import com.tikitaka.naechinso.domain.point.constant.PointType; +import com.tikitaka.naechinso.domain.point.dto.PointChargeRequestDTO; +import com.tikitaka.naechinso.domain.point.dto.PointResponseDTO; +import com.tikitaka.naechinso.domain.point.entity.Point; +import com.tikitaka.naechinso.global.error.ErrorCode; +import com.tikitaka.naechinso.global.error.exception.NotFoundException; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; +import java.util.List; + +@Slf4j @Service +@RequiredArgsConstructor +@Transactional public class PointService { + private final MemberRepository memberRepository; + private final PointRepository pointRepository; + + public PointResponseDTO charge(Member authMember, PointChargeRequestDTO requestDTO) { + Member member = memberRepository.findByMember(authMember) + .orElseThrow(() -> new NotFoundException(ErrorCode.USER_NOT_FOUND)); + + Point point = Point.builder() + .value(requestDTO.getValue()) + .content("포인트 충전") + .type(PointType.CHARGE) + .member(member) + .build(); + + pointRepository.save(point); + + return PointResponseDTO.of(point); + } } diff --git a/src/main/java/com/tikitaka/naechinso/domain/point/constant/PointType.java b/src/main/java/com/tikitaka/naechinso/domain/point/constant/PointType.java new file mode 100644 index 0000000..1b86a8f --- /dev/null +++ b/src/main/java/com/tikitaka/naechinso/domain/point/constant/PointType.java @@ -0,0 +1,25 @@ +package com.tikitaka.naechinso.domain.point.constant; + +import com.fasterxml.jackson.annotation.JsonCreator; +import com.tikitaka.naechinso.domain.member.constant.Role; +import lombok.AllArgsConstructor; +import lombok.Getter; + +@Getter +@AllArgsConstructor +public enum PointType { + CHARGE, + USE + ; + + //Enum Validation 을 위한 코드, enum 에 속하지 않으면 null 리턴 + @JsonCreator + public static PointType fromPointType(String val){ + for(PointType pointType : PointType.values()){ + if(pointType.name().equals(val)){ + return pointType; + } + } + return null; + } +} diff --git a/src/main/java/com/tikitaka/naechinso/domain/point/dto/PointChargeRequestDTO.java b/src/main/java/com/tikitaka/naechinso/domain/point/dto/PointChargeRequestDTO.java new file mode 100644 index 0000000..2666d2c --- /dev/null +++ b/src/main/java/com/tikitaka/naechinso/domain/point/dto/PointChargeRequestDTO.java @@ -0,0 +1,17 @@ +package com.tikitaka.naechinso.domain.point.dto; + +import io.swagger.annotations.ApiModelProperty; +import lombok.*; + +import javax.validation.constraints.Positive; + +@NoArgsConstructor +@AllArgsConstructor +@Getter +@Builder +@ToString +public class PointChargeRequestDTO { + @ApiModelProperty(example = "5000") + @Positive + int value; +} diff --git a/src/main/java/com/tikitaka/naechinso/domain/point/dto/PointResponseDTO.java b/src/main/java/com/tikitaka/naechinso/domain/point/dto/PointResponseDTO.java new file mode 100644 index 0000000..35e1477 --- /dev/null +++ b/src/main/java/com/tikitaka/naechinso/domain/point/dto/PointResponseDTO.java @@ -0,0 +1,26 @@ +package com.tikitaka.naechinso.domain.point.dto; + +import com.tikitaka.naechinso.domain.point.constant.PointType; +import com.tikitaka.naechinso.domain.point.entity.Point; +import lombok.*; + +@NoArgsConstructor +@AllArgsConstructor +@Getter +@Builder +@ToString +public class PointResponseDTO { + private int value; + private String content; + private PointType type; + private String date; + + public static PointResponseDTO of(Point point) { + return PointResponseDTO.builder() + .value(point.getValue()) + .content(point.getContent()) + .type(point.getType()) + .date(point.getCreatedAt().toString()) + .build(); + } +} diff --git a/src/main/java/com/tikitaka/naechinso/domain/point/entity/Point.java b/src/main/java/com/tikitaka/naechinso/domain/point/entity/Point.java index 57bda79..474d5b0 100644 --- a/src/main/java/com/tikitaka/naechinso/domain/point/entity/Point.java +++ b/src/main/java/com/tikitaka/naechinso/domain/point/entity/Point.java @@ -2,6 +2,7 @@ import com.tikitaka.naechinso.domain.member.entity.Member; import com.tikitaka.naechinso.domain.member.entity.MemberDetail; +import com.tikitaka.naechinso.domain.point.constant.PointType; import com.tikitaka.naechinso.global.config.entity.BaseEntity; import com.tikitaka.naechinso.global.config.entity.BaseTimeEntity; import lombok.*; @@ -26,13 +27,14 @@ public class Point extends BaseEntity { private Long id; @Column(name = "poi_value") - private Long value; + private int value; @Column(name = "poi_content") private String content; @Column(name = "poi_type") - private String type; + @Enumerated(EnumType.STRING) + private PointType type; @ManyToOne(fetch = FetchType.LAZY) @JoinColumn(name = "mem_id") diff --git a/src/main/java/com/tikitaka/naechinso/domain/recommend/RecommendRepository.java b/src/main/java/com/tikitaka/naechinso/domain/recommend/RecommendRepository.java index 9e03e62..b56c77f 100644 --- a/src/main/java/com/tikitaka/naechinso/domain/recommend/RecommendRepository.java +++ b/src/main/java/com/tikitaka/naechinso/domain/recommend/RecommendRepository.java @@ -10,7 +10,6 @@ import java.util.Optional; import java.util.UUID; -@Repository public interface RecommendRepository extends JpaRepository { List findAllByReceiver_Id(Long id); List findAllByReceiverPhone(String phone); diff --git a/src/main/java/com/tikitaka/naechinso/domain/recommend/dto/RecommendResponseDTO.java b/src/main/java/com/tikitaka/naechinso/domain/recommend/dto/RecommendResponseDTO.java index e99b841..b72cf5b 100644 --- a/src/main/java/com/tikitaka/naechinso/domain/recommend/dto/RecommendResponseDTO.java +++ b/src/main/java/com/tikitaka/naechinso/domain/recommend/dto/RecommendResponseDTO.java @@ -19,6 +19,8 @@ public class RecommendResponseDTO { private Gender gender; + private int age; + private String meet; private String appeal; @@ -54,6 +56,7 @@ public static RecommendResponseDTO of(Recommend recommend) { .receiverId(receiverId) .name(recommend.getReceiverName()) .gender(recommend.getReceiverGender()) + .age(recommend.getReceiverAge()) .meet(recommend.getReceiverMeet()) .appeal(recommend.getReceiverAppeal()) .appealDetail(recommend.getReceiverAppealDetail()) From edc8019a6959979bda9aa90d41ec805bc836b976 Mon Sep 17 00:00:00 2001 From: gengminy Date: Thu, 27 Oct 2022 16:39:34 +0900 Subject: [PATCH 43/72] =?UTF-8?q?:rocket:=20feat(point):=20=ED=8F=AC?= =?UTF-8?q?=EC=9D=B8=ED=8A=B8=20=EC=B6=A9=EC=A0=84=20=EB=B0=8F=20=EC=82=AC?= =?UTF-8?q?=EC=9A=A9=20=EA=B5=AC=ED=98=84=20#48?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../member/dto/MemberCommonResponseDTO.java | 3 + .../member/dto/MemberDetailResponseDTO.java | 1 - .../domain/member/entity/Member.java | 37 +++++++++++ .../domain/member/entity/MemberDetail.java | 4 -- .../domain/point/PointController.java | 23 +++++-- .../naechinso/domain/point/PointService.java | 37 ++++++++++- .../point/dto/PointHistoryResponseDTO.java | 61 +++++++++++++++++++ .../domain/point/dto/PointResponseDTO.java | 9 ++- .../global/config/swagger/SwaggerConfig.java | 1 - .../naechinso/global/error/ErrorCode.java | 3 + 10 files changed, 164 insertions(+), 15 deletions(-) create mode 100644 src/main/java/com/tikitaka/naechinso/domain/point/dto/PointHistoryResponseDTO.java diff --git a/src/main/java/com/tikitaka/naechinso/domain/member/dto/MemberCommonResponseDTO.java b/src/main/java/com/tikitaka/naechinso/domain/member/dto/MemberCommonResponseDTO.java index a15927b..e480194 100644 --- a/src/main/java/com/tikitaka/naechinso/domain/member/dto/MemberCommonResponseDTO.java +++ b/src/main/java/com/tikitaka/naechinso/domain/member/dto/MemberCommonResponseDTO.java @@ -54,6 +54,8 @@ public class MemberCommonResponseDTO { private Boolean eduAccepted; + private long point; + public static MemberCommonResponseDTO of(Member member) { return MemberCommonResponseDTO.builder() .phone(member.getPhone()) @@ -71,6 +73,7 @@ public static MemberCommonResponseDTO of(Member member) { .eduLevel(member.getEduLevel()) .eduImage(member.getEduImage()) .eduAccepted(member.getEduAccepted()) + .point(member.getPoint()) .build(); } } diff --git a/src/main/java/com/tikitaka/naechinso/domain/member/dto/MemberDetailResponseDTO.java b/src/main/java/com/tikitaka/naechinso/domain/member/dto/MemberDetailResponseDTO.java index 4ce1f78..284d2a7 100644 --- a/src/main/java/com/tikitaka/naechinso/domain/member/dto/MemberDetailResponseDTO.java +++ b/src/main/java/com/tikitaka/naechinso/domain/member/dto/MemberDetailResponseDTO.java @@ -95,7 +95,6 @@ private static MemberDetailResponseDTO buildDetail(MemberDetail detail) { .hobby(detail.getHobby()) .style(detail.getStyle()) .images(detail.getImages()) - .point(detail.getPoint()) .build(); } diff --git a/src/main/java/com/tikitaka/naechinso/domain/member/entity/Member.java b/src/main/java/com/tikitaka/naechinso/domain/member/entity/Member.java index e148a96..389f0f0 100644 --- a/src/main/java/com/tikitaka/naechinso/domain/member/entity/Member.java +++ b/src/main/java/com/tikitaka/naechinso/domain/member/entity/Member.java @@ -9,10 +9,12 @@ import com.tikitaka.naechinso.domain.member.dto.MemberUpdateEduRequestDTO; import com.tikitaka.naechinso.domain.member.dto.MemberUpdateJobRequestDTO; import com.tikitaka.naechinso.domain.pending.entity.Pending; +import com.tikitaka.naechinso.domain.point.constant.PointType; import com.tikitaka.naechinso.domain.point.entity.Point; import com.tikitaka.naechinso.domain.recommend.entity.Recommend; import com.tikitaka.naechinso.global.config.entity.BaseEntity; import com.tikitaka.naechinso.global.error.ErrorCode; +import com.tikitaka.naechinso.global.error.exception.BadRequestException; import com.tikitaka.naechinso.global.error.exception.UnauthorizedException; import lombok.*; @@ -113,6 +115,10 @@ public class Member extends BaseEntity { @Builder.Default private Boolean joinAccepted = false; + @Column(name = "mem_point") + @Builder.Default + private Long point = 0L; + //멤버 디테일 정보 @OneToOne(mappedBy = "member") @JoinColumn(name = "mem_detail") @@ -197,6 +203,37 @@ public List updateImage(List images) { return this.detail.updateImage(images); } + /** 포인트를 충전합니다 */ + public void chargePoint(long value) { + this.point += value; + } + + /** 포인트를 사용합니다 */ + public void usePoint(long value) { + if (this.point - value >= 0) { + this.point -= value; + } else { + throw new BadRequestException(ErrorCode.POINT_NOT_ENOUGH); + } + } + + public boolean validatePoint() { + long sum = 0; + for (Point pointHistory : this.points) { + if (pointHistory.getType() == PointType.CHARGE) { + sum += pointHistory.getValue(); + } else if (pointHistory.getType() == PointType.USE){ + sum -= pointHistory.getValue(); + } + } + + if (sum != point) { + System.out.println("잔여 포인트 검증 오류"); + return false; + } + return true; + } + public void acceptJobImage() { this.jobAccepted = true; } diff --git a/src/main/java/com/tikitaka/naechinso/domain/member/entity/MemberDetail.java b/src/main/java/com/tikitaka/naechinso/domain/member/entity/MemberDetail.java index e111ccd..f52e710 100644 --- a/src/main/java/com/tikitaka/naechinso/domain/member/entity/MemberDetail.java +++ b/src/main/java/com/tikitaka/naechinso/domain/member/entity/MemberDetail.java @@ -75,10 +75,6 @@ public class MemberDetail extends BaseEntity { @Column(name = "mem_image_accepted") private Boolean image_accepted; - @Column(name = "mem_point") - @Builder.Default - private Long point = 0L; - // MemberDetail 을 소유한 Member 와 연결 // Member Entity 와 1:1 조인 // Member PK 그대로 사용 diff --git a/src/main/java/com/tikitaka/naechinso/domain/point/PointController.java b/src/main/java/com/tikitaka/naechinso/domain/point/PointController.java index b61c655..74821d9 100644 --- a/src/main/java/com/tikitaka/naechinso/domain/point/PointController.java +++ b/src/main/java/com/tikitaka/naechinso/domain/point/PointController.java @@ -3,10 +3,12 @@ import com.tikitaka.naechinso.domain.member.dto.MemberCommonResponseDTO; import com.tikitaka.naechinso.domain.member.entity.Member; import com.tikitaka.naechinso.domain.point.dto.PointChargeRequestDTO; +import com.tikitaka.naechinso.domain.point.dto.PointHistoryResponseDTO; import com.tikitaka.naechinso.domain.point.dto.PointResponseDTO; import com.tikitaka.naechinso.global.annotation.AuthMember; import com.tikitaka.naechinso.global.config.CommonApiResponse; import io.swagger.annotations.ApiOperation; +import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; import org.springframework.stereotype.Controller; import org.springframework.web.bind.annotation.*; @@ -15,25 +17,34 @@ @Slf4j @RestController @RequestMapping("/point") +@RequiredArgsConstructor public class PointController { - private PointService pointService; + private final PointService pointService; @GetMapping @ApiOperation(value = "유저 자신의 포인트 충전 / 사용 내역을 모두 가져온다 (AccessToken)") - public CommonApiResponse getPointHistory( + public CommonApiResponse getPointHistory( @ApiIgnore @AuthMember Member member ) { -// return CommonApiResponse.of(pointService.readCommonMember(member)); - return null; + return CommonApiResponse.of(pointService.getPointHistory(member)); } @PostMapping("/charge") - @ApiOperation(value = "유저 자신의 모든 정보를 가져온다 (AccessToken)") - public CommonApiResponse getMyInformation( + @ApiOperation(value = "포인트 충전을 요청한다 (AccessToken)") + public CommonApiResponse chargePoint( @ApiIgnore @AuthMember Member member, @RequestBody PointChargeRequestDTO requestDTO ) { return CommonApiResponse.of(pointService.charge(member, requestDTO)); } + + @PostMapping("/use") + @ApiOperation(value = "포인트 사용을 요청한다 (AccessToken)") + public CommonApiResponse usePoint( + @ApiIgnore @AuthMember Member member, + @RequestBody PointChargeRequestDTO requestDTO + ) { + return CommonApiResponse.of(pointService.use(member, requestDTO)); + } } diff --git a/src/main/java/com/tikitaka/naechinso/domain/point/PointService.java b/src/main/java/com/tikitaka/naechinso/domain/point/PointService.java index 49fb967..92f954a 100644 --- a/src/main/java/com/tikitaka/naechinso/domain/point/PointService.java +++ b/src/main/java/com/tikitaka/naechinso/domain/point/PointService.java @@ -4,6 +4,7 @@ import com.tikitaka.naechinso.domain.member.entity.Member; import com.tikitaka.naechinso.domain.point.constant.PointType; import com.tikitaka.naechinso.domain.point.dto.PointChargeRequestDTO; +import com.tikitaka.naechinso.domain.point.dto.PointHistoryResponseDTO; import com.tikitaka.naechinso.domain.point.dto.PointResponseDTO; import com.tikitaka.naechinso.domain.point.entity.Point; import com.tikitaka.naechinso.global.error.ErrorCode; @@ -23,6 +24,10 @@ public class PointService { private final MemberRepository memberRepository; private final PointRepository pointRepository; + public PointHistoryResponseDTO getPointHistory(Member authMember) { + return PointHistoryResponseDTO.of(pointRepository.findAllByMember(authMember)); + } + public PointResponseDTO charge(Member authMember, PointChargeRequestDTO requestDTO) { Member member = memberRepository.findByMember(authMember) .orElseThrow(() -> new NotFoundException(ErrorCode.USER_NOT_FOUND)); @@ -34,8 +39,38 @@ public PointResponseDTO charge(Member authMember, PointChargeRequestDTO requestD .member(member) .build(); + //포인트 충전 + member.chargePoint(requestDTO.getValue()); + + memberRepository.save(member); + pointRepository.save(point); + + return PointResponseDTO.of(member, point); + } + + /** + * 포인트를 사용한다 + * @// TODO: 2022/10/27 상품 엔티티를 만들어서 결제하는 것 필요 + * @param authMember + * @param requestDTO + * @return + */ + public PointResponseDTO use(Member authMember, PointChargeRequestDTO requestDTO) { + Member member = memberRepository.findByMember(authMember) + .orElseThrow(() -> new NotFoundException(ErrorCode.USER_NOT_FOUND)); + + Point point = Point.builder() + .value(requestDTO.getValue()) + .content("포인트 사용") + .type(PointType.USE) + .member(member) + .build(); + + member.usePoint(requestDTO.getValue()); + + memberRepository.save(member); pointRepository.save(point); - return PointResponseDTO.of(point); + return PointResponseDTO.of(member, point); } } diff --git a/src/main/java/com/tikitaka/naechinso/domain/point/dto/PointHistoryResponseDTO.java b/src/main/java/com/tikitaka/naechinso/domain/point/dto/PointHistoryResponseDTO.java new file mode 100644 index 0000000..7c71e04 --- /dev/null +++ b/src/main/java/com/tikitaka/naechinso/domain/point/dto/PointHistoryResponseDTO.java @@ -0,0 +1,61 @@ +package com.tikitaka.naechinso.domain.point.dto; + +import com.tikitaka.naechinso.domain.member.entity.Member; +import com.tikitaka.naechinso.domain.point.constant.PointType; +import com.tikitaka.naechinso.domain.point.entity.Point; +import lombok.*; + +import java.util.ArrayList; +import java.util.List; + +@NoArgsConstructor +@AllArgsConstructor +@Getter +@Builder +@ToString +public class PointHistoryResponseDTO { + //포인트 이력 + private List history; + + //남은 포인트 + private long point = 0; + + @NoArgsConstructor + @AllArgsConstructor + @Getter + @Builder + @ToString + private static class History { + private long value; + private String content; + private PointType type; + private String date; + //잔액 기록 + private long point; + } + + public static PointHistoryResponseDTO of(List points) { + List historyList = new ArrayList<>(); + long pointSum = 0; + for (Point pointHistory : points) { + if (pointHistory.getType() == PointType.CHARGE) { + pointSum += pointHistory.getValue(); + } else if (pointHistory.getType() == PointType.USE) { + pointSum -= pointHistory.getValue(); + } + + historyList.add(History.builder() + .content(pointHistory.getContent()) + .date(pointHistory.getCreatedAt().toString()) + .type(pointHistory.getType()) + .value(pointHistory.getValue()) + .point(pointSum) + .build()); + } + + return PointHistoryResponseDTO.builder() + .history(historyList) + .point(pointSum) + .build(); + } +} diff --git a/src/main/java/com/tikitaka/naechinso/domain/point/dto/PointResponseDTO.java b/src/main/java/com/tikitaka/naechinso/domain/point/dto/PointResponseDTO.java index 35e1477..e8d5607 100644 --- a/src/main/java/com/tikitaka/naechinso/domain/point/dto/PointResponseDTO.java +++ b/src/main/java/com/tikitaka/naechinso/domain/point/dto/PointResponseDTO.java @@ -1,5 +1,6 @@ package com.tikitaka.naechinso.domain.point.dto; +import com.tikitaka.naechinso.domain.member.entity.Member; import com.tikitaka.naechinso.domain.point.constant.PointType; import com.tikitaka.naechinso.domain.point.entity.Point; import lombok.*; @@ -10,17 +11,21 @@ @Builder @ToString public class PointResponseDTO { - private int value; + private long value; private String content; private PointType type; private String date; - public static PointResponseDTO of(Point point) { + // 유저 잔여 포인트 + private long point; + + public static PointResponseDTO of(Member member, Point point) { return PointResponseDTO.builder() .value(point.getValue()) .content(point.getContent()) .type(point.getType()) .date(point.getCreatedAt().toString()) + .point(member.getPoint()) .build(); } } diff --git a/src/main/java/com/tikitaka/naechinso/global/config/swagger/SwaggerConfig.java b/src/main/java/com/tikitaka/naechinso/global/config/swagger/SwaggerConfig.java index 010b5a1..6c4ce87 100644 --- a/src/main/java/com/tikitaka/naechinso/global/config/swagger/SwaggerConfig.java +++ b/src/main/java/com/tikitaka/naechinso/global/config/swagger/SwaggerConfig.java @@ -72,4 +72,3 @@ private Set getProduceContentTypes() { return produces; } } -//swagger: http://localhost:8000/swagger-ui/index.html \ No newline at end of file diff --git a/src/main/java/com/tikitaka/naechinso/global/error/ErrorCode.java b/src/main/java/com/tikitaka/naechinso/global/error/ErrorCode.java index 66523b1..5111aa7 100644 --- a/src/main/java/com/tikitaka/naechinso/global/error/ErrorCode.java +++ b/src/main/java/com/tikitaka/naechinso/global/error/ErrorCode.java @@ -94,6 +94,9 @@ public enum ErrorCode { CARD_LIMIT_EXCEED(BAD_REQUEST, "CARD002", "일일 추천 카드 한도를 초과했습니다"), + /* 포인트 관련 */ + POINT_NOT_ENOUGH(BAD_REQUEST, "POINT000", "포인트가 부족합니다"); + ; private final HttpStatus httpStatus; From b00721e870833fb967cc9df86f52dcbca6fa09f1 Mon Sep 17 00:00:00 2001 From: gengminy Date: Thu, 27 Oct 2022 17:15:02 +0900 Subject: [PATCH 44/72] =?UTF-8?q?:rocket:=20feat(notify):=20=EC=95=8C?= =?UTF-8?q?=EB=A6=BC=20=EC=97=94=ED=8B=B0=ED=8B=B0=20=EA=B5=AC=ED=98=84=20?= =?UTF-8?q?#50?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../domain/member/entity/Member.java | 7 +++ .../notification/NotificationController.java | 28 +++++++++++ .../notification/NotificationRepository.java | 7 +++ .../notification/NotificationService.java | 14 ++++++ .../constant/NotificationType.java | 26 ++++++++++ .../dto/NotificationHistoryResponseDTO.java | 47 +++++++++++++++++++ .../notification/entity/Notification.java | 39 +++++++++++++++ .../domain/pending/PendingRepository.java | 1 - 8 files changed, 168 insertions(+), 1 deletion(-) create mode 100644 src/main/java/com/tikitaka/naechinso/domain/notification/NotificationController.java create mode 100644 src/main/java/com/tikitaka/naechinso/domain/notification/NotificationRepository.java create mode 100644 src/main/java/com/tikitaka/naechinso/domain/notification/NotificationService.java create mode 100644 src/main/java/com/tikitaka/naechinso/domain/notification/constant/NotificationType.java create mode 100644 src/main/java/com/tikitaka/naechinso/domain/notification/dto/NotificationHistoryResponseDTO.java create mode 100644 src/main/java/com/tikitaka/naechinso/domain/notification/entity/Notification.java diff --git a/src/main/java/com/tikitaka/naechinso/domain/member/entity/Member.java b/src/main/java/com/tikitaka/naechinso/domain/member/entity/Member.java index 389f0f0..b410b03 100644 --- a/src/main/java/com/tikitaka/naechinso/domain/member/entity/Member.java +++ b/src/main/java/com/tikitaka/naechinso/domain/member/entity/Member.java @@ -8,6 +8,7 @@ import com.tikitaka.naechinso.domain.member.dto.MemberUpdateCommonRequestDTO; import com.tikitaka.naechinso.domain.member.dto.MemberUpdateEduRequestDTO; import com.tikitaka.naechinso.domain.member.dto.MemberUpdateJobRequestDTO; +import com.tikitaka.naechinso.domain.notification.entity.Notification; import com.tikitaka.naechinso.domain.pending.entity.Pending; import com.tikitaka.naechinso.domain.point.constant.PointType; import com.tikitaka.naechinso.domain.point.entity.Point; @@ -135,6 +136,12 @@ public class Member extends BaseEntity { @JsonIgnore private List points = new ArrayList<>(); + //내 가입 대기 정보 + @OneToMany(mappedBy = "member") + @ToString.Exclude + @JsonIgnore + private List notifications = new ArrayList<>(); + //내가 보낸 호감 내역 @OneToMany(mappedBy = "fromMember") @ToString.Exclude diff --git a/src/main/java/com/tikitaka/naechinso/domain/notification/NotificationController.java b/src/main/java/com/tikitaka/naechinso/domain/notification/NotificationController.java new file mode 100644 index 0000000..79628a7 --- /dev/null +++ b/src/main/java/com/tikitaka/naechinso/domain/notification/NotificationController.java @@ -0,0 +1,28 @@ +package com.tikitaka.naechinso.domain.notification; + +import com.tikitaka.naechinso.domain.member.entity.Member; +import com.tikitaka.naechinso.global.annotation.AuthMember; +import com.tikitaka.naechinso.global.config.CommonApiResponse; +import io.swagger.annotations.ApiOperation; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; +import springfox.documentation.annotations.ApiIgnore; + +@Slf4j +@RestController +@RequestMapping("/notify") +@RequiredArgsConstructor +public class NotificationController { + private final NotificationService notificationService; + + @GetMapping + @ApiOperation(value = "유저 자신의 모든 알림 기록을 (AccessToken)") + public CommonApiResponse findAllNotification( + @ApiIgnore @AuthMember Member member + ) { + return CommonApiResponse.of(true); + } +} diff --git a/src/main/java/com/tikitaka/naechinso/domain/notification/NotificationRepository.java b/src/main/java/com/tikitaka/naechinso/domain/notification/NotificationRepository.java new file mode 100644 index 0000000..6c2551a --- /dev/null +++ b/src/main/java/com/tikitaka/naechinso/domain/notification/NotificationRepository.java @@ -0,0 +1,7 @@ +package com.tikitaka.naechinso.domain.notification; + +import com.tikitaka.naechinso.domain.notification.entity.Notification; +import org.springframework.data.jpa.repository.JpaRepository; + +public interface NotificationRepository extends JpaRepository { +} diff --git a/src/main/java/com/tikitaka/naechinso/domain/notification/NotificationService.java b/src/main/java/com/tikitaka/naechinso/domain/notification/NotificationService.java new file mode 100644 index 0000000..57f5464 --- /dev/null +++ b/src/main/java/com/tikitaka/naechinso/domain/notification/NotificationService.java @@ -0,0 +1,14 @@ +package com.tikitaka.naechinso.domain.notification; + +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +@Slf4j +@Service +@RequiredArgsConstructor +@Transactional +public class NotificationService { + private final NotificationRepository notificationRepository; +} diff --git a/src/main/java/com/tikitaka/naechinso/domain/notification/constant/NotificationType.java b/src/main/java/com/tikitaka/naechinso/domain/notification/constant/NotificationType.java new file mode 100644 index 0000000..2129fde --- /dev/null +++ b/src/main/java/com/tikitaka/naechinso/domain/notification/constant/NotificationType.java @@ -0,0 +1,26 @@ +package com.tikitaka.naechinso.domain.notification.constant; + +import com.fasterxml.jackson.annotation.JsonCreator; + +public enum NotificationType { + ALARM, + + //매칭 알람 + MATCH, + + //마케팅 메세지 + MARKETING + + ; + + //Enum Validation 을 위한 코드, enum 에 속하지 않으면 null 리턴 + @JsonCreator + public static NotificationType fromNotificationType(String val){ + for(NotificationType notificationType : NotificationType.values()){ + if(notificationType.name().equals(val)){ + return notificationType; + } + } + return null; + } +} diff --git a/src/main/java/com/tikitaka/naechinso/domain/notification/dto/NotificationHistoryResponseDTO.java b/src/main/java/com/tikitaka/naechinso/domain/notification/dto/NotificationHistoryResponseDTO.java new file mode 100644 index 0000000..659554d --- /dev/null +++ b/src/main/java/com/tikitaka/naechinso/domain/notification/dto/NotificationHistoryResponseDTO.java @@ -0,0 +1,47 @@ +package com.tikitaka.naechinso.domain.notification.dto; + +import com.tikitaka.naechinso.domain.notification.constant.NotificationType; +import com.tikitaka.naechinso.domain.notification.entity.Notification; +import com.tikitaka.naechinso.domain.point.dto.PointHistoryResponseDTO; +import lombok.*; + +import java.util.ArrayList; +import java.util.List; + +@NoArgsConstructor +@AllArgsConstructor +@Getter +@Builder +@ToString +public class NotificationHistoryResponseDTO { + //알림 이력 + private List history; + + @NoArgsConstructor + @AllArgsConstructor + @Getter + @Builder + @ToString + private static class History { + private NotificationType type; + private String title; + private String content; + private String date; + } + + public static NotificationHistoryResponseDTO of(List notifications) { + List historyList = new ArrayList<>(); + for (Notification notification : notifications) { + historyList.add(History.builder() + .type(notification.getType()) + .title(notification.getTitle()) + .content(notification.getContent()) + .date(notification.getCreatedAt().toString()) + .build()); + } + + return NotificationHistoryResponseDTO.builder() + .history(historyList) + .build(); + } +} diff --git a/src/main/java/com/tikitaka/naechinso/domain/notification/entity/Notification.java b/src/main/java/com/tikitaka/naechinso/domain/notification/entity/Notification.java new file mode 100644 index 0000000..660ccd5 --- /dev/null +++ b/src/main/java/com/tikitaka/naechinso/domain/notification/entity/Notification.java @@ -0,0 +1,39 @@ +package com.tikitaka.naechinso.domain.notification.entity; + +import com.fasterxml.jackson.annotation.JsonIgnore; +import com.tikitaka.naechinso.domain.member.entity.Member; +import com.tikitaka.naechinso.domain.notification.constant.NotificationType; +import com.tikitaka.naechinso.global.config.entity.BaseEntity; +import lombok.*; + +import javax.persistence.*; + +@Entity +@Table(name = "Notification") +@Getter +@Builder +@AllArgsConstructor +@NoArgsConstructor +@ToString +public class Notification extends BaseEntity { + @Id + @Column(name = "not_id") + @GeneratedValue + private Long id; + + /* 알림 주인 */ + @ManyToOne(fetch = FetchType.LAZY) + @JoinColumn(name = "mem_id") + @JsonIgnore + private Member member; + + @Column(name = "not_type") + @Enumerated(EnumType.STRING) + private NotificationType type; + + @Column(name = "not_title") + private String title; + + @Column(name = "not_content") + private String content; +} diff --git a/src/main/java/com/tikitaka/naechinso/domain/pending/PendingRepository.java b/src/main/java/com/tikitaka/naechinso/domain/pending/PendingRepository.java index 48a19a3..4e82737 100644 --- a/src/main/java/com/tikitaka/naechinso/domain/pending/PendingRepository.java +++ b/src/main/java/com/tikitaka/naechinso/domain/pending/PendingRepository.java @@ -6,7 +6,6 @@ import java.util.List; -@Repository public interface PendingRepository extends JpaRepository { List findAllByMemberId(Long memberId); From 96549e17d205d57342e6f956bb15e34c31bd66c5 Mon Sep 17 00:00:00 2001 From: gengminy Date: Sun, 30 Oct 2022 15:29:28 +0900 Subject: [PATCH 45/72] =?UTF-8?q?:rocket:=20feat(notify):=20=ED=91=B8?= =?UTF-8?q?=EC=8B=9C=20=EC=95=8C=EB=A6=BC=20=ED=94=84=EB=A1=9C=ED=86=A0?= =?UTF-8?q?=ED=83=80=EC=9E=85=20#50?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .gitignore | 3 +- build.gradle | 3 + .../naechinso/domain/TestController.java | 2 +- .../domain/match/MatchController.java | 9 ++ .../domain/match/MatchEventListener.java | 133 +++++++++++++++++ .../naechinso/domain/match/MatchService.java | 69 ++++++++- .../naechinso/domain/match/entity/Match.java | 4 + .../domain/match/event/MatchLikeEvent.java | 12 ++ .../domain/match/event/MatchOpenEvent.java | 12 ++ .../match/event/MatchResponseEvent.java | 13 ++ .../domain/member/entity/Member.java | 27 +++- .../notification/NotificationService.java | 14 -- .../global/config/async/AsyncConfig.java | 28 ++++ .../naechinso/global/error/ErrorCode.java | 10 +- .../global/util/CustomStringUtil.java | 4 +- .../notification/NotificationController.java | 2 +- .../notification/NotificationRepository.java | 4 +- .../notification/NotificationService.java | 140 ++++++++++++++++++ .../constant/NotificationType.java | 5 +- .../dto/NotificationHistoryResponseDTO.java | 7 +- .../notification/entity/Notification.java | 16 +- src/main/resources/application.yml | 5 + 22 files changed, 477 insertions(+), 45 deletions(-) create mode 100644 src/main/java/com/tikitaka/naechinso/domain/match/MatchEventListener.java create mode 100644 src/main/java/com/tikitaka/naechinso/domain/match/event/MatchLikeEvent.java create mode 100644 src/main/java/com/tikitaka/naechinso/domain/match/event/MatchOpenEvent.java create mode 100644 src/main/java/com/tikitaka/naechinso/domain/match/event/MatchResponseEvent.java delete mode 100644 src/main/java/com/tikitaka/naechinso/domain/notification/NotificationService.java create mode 100644 src/main/java/com/tikitaka/naechinso/global/config/async/AsyncConfig.java rename src/main/java/com/tikitaka/naechinso/{domain => infra}/notification/NotificationController.java (94%) rename src/main/java/com/tikitaka/naechinso/{domain => infra}/notification/NotificationRepository.java (54%) create mode 100644 src/main/java/com/tikitaka/naechinso/infra/notification/NotificationService.java rename src/main/java/com/tikitaka/naechinso/{domain => infra}/notification/constant/NotificationType.java (85%) rename src/main/java/com/tikitaka/naechinso/{domain => infra}/notification/dto/NotificationHistoryResponseDTO.java (80%) rename src/main/java/com/tikitaka/naechinso/{domain => infra}/notification/entity/Notification.java (66%) diff --git a/.gitignore b/.gitignore index 0021bf5..ff020ef 100644 --- a/.gitignore +++ b/.gitignore @@ -42,4 +42,5 @@ out/ !**/src/main/resources/application-**.yml src/main/resources/application-dev.yml src/main/resources/application-local.yml -src/main/resources/application-prod.yml \ No newline at end of file +src/main/resources/application-prod.yml +/src/main/resources/**.json diff --git a/build.gradle b/build.gradle index 4124161..e96ca2f 100644 --- a/build.gradle +++ b/build.gradle @@ -40,6 +40,9 @@ dependencies { //AWS S3 implementation 'io.awspring.cloud:spring-cloud-starter-aws:2.4.2' + //Firebase FCM + implementation group: 'com.google.firebase', name: 'firebase-admin', version: '6.8.1' + //jwt implementation group: 'io.jsonwebtoken', name: 'jjwt', version: '0.9.1' diff --git a/src/main/java/com/tikitaka/naechinso/domain/TestController.java b/src/main/java/com/tikitaka/naechinso/domain/TestController.java index 9d87fc2..70c394a 100644 --- a/src/main/java/com/tikitaka/naechinso/domain/TestController.java +++ b/src/main/java/com/tikitaka/naechinso/domain/TestController.java @@ -462,7 +462,7 @@ public CommonApiResponse createMultipleMembers() { @GetMapping("/create-match") @ApiOperation(value = "[*TEST*] 나에게 호감을 보낸 매칭을 하나 생성한다") - public CommonApiResponse dropAllTable( + public CommonApiResponse createMatch( @ApiIgnore @AuthMember Member member ) { Match match = Match.builder() diff --git a/src/main/java/com/tikitaka/naechinso/domain/match/MatchController.java b/src/main/java/com/tikitaka/naechinso/domain/match/MatchController.java index 3123a0e..7b32fe5 100644 --- a/src/main/java/com/tikitaka/naechinso/domain/match/MatchController.java +++ b/src/main/java/com/tikitaka/naechinso/domain/match/MatchController.java @@ -82,6 +82,15 @@ public CommonApiResponse accept( return CommonApiResponse.of(matchService.accept(member, id)); } + @PostMapping("/{id}/reject") + @ApiOperation(value = "해당 상대의 호감을 거절한다 (AccessToken)") + public CommonApiResponse reject( + @PathVariable("id") Long id, + @ApiIgnore @AuthMember Member member + ) { + return CommonApiResponse.of(matchService.reject(member, id)); + } + @PostMapping("/{id}/open") @ApiOperation(value = "현재 호감을 보낸 상대의 번호 오픈을 요청한다 (AccessToken)") public CommonApiResponse openPhone( diff --git a/src/main/java/com/tikitaka/naechinso/domain/match/MatchEventListener.java b/src/main/java/com/tikitaka/naechinso/domain/match/MatchEventListener.java new file mode 100644 index 0000000..4840614 --- /dev/null +++ b/src/main/java/com/tikitaka/naechinso/domain/match/MatchEventListener.java @@ -0,0 +1,133 @@ +package com.tikitaka.naechinso.domain.match; + +import com.tikitaka.naechinso.domain.match.event.MatchLikeEvent; +import com.tikitaka.naechinso.domain.match.event.MatchOpenEvent; +import com.tikitaka.naechinso.domain.match.event.MatchResponseEvent; +import com.tikitaka.naechinso.domain.member.entity.Member; +import com.tikitaka.naechinso.global.util.CustomStringUtil; +import com.tikitaka.naechinso.infra.notification.NotificationRepository; +import com.tikitaka.naechinso.infra.notification.NotificationService; +import com.tikitaka.naechinso.infra.notification.constant.NotificationType; +import lombok.RequiredArgsConstructor; +import org.springframework.context.event.EventListener; +import org.springframework.scheduling.annotation.Async; +import org.springframework.stereotype.Component; + +import javax.transaction.Transactional; +import java.util.Arrays; + +// EventListener +@Component +@Async("match") +@RequiredArgsConstructor +@Transactional +public class MatchEventListener { + private final NotificationService notificationService; + private final NotificationRepository notificationRepository; + + /** + * 호감 보내기에 대한 이벤트 + * @param matchLikeEvent 수신 송신 멤버를 담은 DTO + */ + @EventListener + public void handleLikeEvent(MatchLikeEvent matchLikeEvent) { + final Member sender = matchLikeEvent.getSender(); + final String senderHideName = CustomStringUtil.hideName(sender.getName()); + final Member receiver = matchLikeEvent.getReceiver(); + final String receiverFcmToken = receiver.getFcmToken(); + + final String title = "호감 전달"; + final String content = senderHideName + "이(가) 너가 마음에 든대 🎉"; + + //FcmToken 비어있으면 로그아웃 또는 푸시알림 거부 -> 푸시 알림을 보내지 않음 + if (!receiverFcmToken.isBlank() && receiver.isAcceptsPush()) { + notificationService.sendByToken(receiverFcmToken, title, content); + } + + //알림 히스토리는 저장 + notificationService.createNotification(receiver.getId(), title, content, NotificationType.MATCH); + } + + /** + * 호감 수락 및 거절에 대한 이벤트 + * @param matchResponseEvent 수신 송신 멤버를 담은 DTO + */ + @EventListener + public void handleResponseEvent(MatchResponseEvent matchResponseEvent) { + final Member sender = matchResponseEvent.getSender(); + final String senderFcmToken = sender.getFcmToken(); + final Member receiver = matchResponseEvent.getReceiver(); + final String receiverHideName = CustomStringUtil.hideName(receiver.getName()); + + final String title = matchResponseEvent.isAccepted() ? "호감 수락" : "호감 거절"; + final String content = receiverHideName + + (matchResponseEvent.isAccepted() ? "도 너가 좋대 🎉" : "이(가) 너의 호감을 정중히 거절했어"); + + if (!senderFcmToken.isBlank() && sender.isAcceptsPush()) { + notificationService.sendByToken(senderFcmToken, title, content); + } + + notificationService.createNotification(sender.getId(), title, content, NotificationType.MATCH); + } + + + /** + * 번호 오픈 이벤트 + * @param matchOpenEvent 수신 송신 멤버를 담은 DTO + */ + @EventListener + public void handleOpenEvent(MatchOpenEvent matchOpenEvent) { + final Member opener = matchOpenEvent.getOpener(); + final String openerFcmToken = opener.getFcmToken(); + final Member opposite = matchOpenEvent.getOpposite(); + final String oppositeFcmToken = opposite.getFcmToken(); + + //번호 오픈 이후부터는 이름을 가리지 않음 + final String title = "호감 수락"; + final String content = opener.getName() + "이(가) 번호를 오픈했어!"; + + if (!openerFcmToken.isBlank() && opener.isAcceptsPush()) { + notificationService.sendByToken(openerFcmToken, title, content); + } + if (!oppositeFcmToken.isBlank() && opposite.isAcceptsPush()) { + notificationService.sendByToken(oppositeFcmToken, title, content); + } + + notificationService.createNotificationList( + Arrays.asList(opener.getId(), opposite.getId()), title, content, NotificationType.MATCH); + } + +// +// @EventListener +// public void handleMatchCompleteEvent(MatchCompleteEvent matchCompleteEvent){ +// +// // 알림 보낼 멤버 목록 +// List memberList = matchCompleteEvent.getMemberList(); +// +// // 로그아웃 안한 회원의 fcmToken 뽑기 +// // 로그아웃한 회원들의 fcmToken 필드는 "" 공백입니다. +// List fcmTokenList = memberList +// .stream() +// .map(Member::getFcmToken) +// .filter(fcmToken -> !fcmToken.isBlank()).collect(Collectors.toList()); +// +// // 로그아웃 안한 대상에게 알림 보내기 +// if (fcmTokenList.size() != 0){ +// notificationService.sendByTokenList(fcmTokenList); +// } +// +// // 알림 엔티티 생성 // +// List notificationList = memberList +// .stream() +// .map(member -> Notification.builder() +// .type(NotificationType.MATCH) +// .title("매칭 알림") +// .content("매칭이 성사되었습니다") +// .member(member) +// .build()) +// .collect(Collectors.toList()); +// // 알림 벌크 저장 +//// notificationRepository.insertNotificationWithTeamId(notificationList); +// } + +} diff --git a/src/main/java/com/tikitaka/naechinso/domain/match/MatchService.java b/src/main/java/com/tikitaka/naechinso/domain/match/MatchService.java index 4aeaf0e..34dea74 100644 --- a/src/main/java/com/tikitaka/naechinso/domain/match/MatchService.java +++ b/src/main/java/com/tikitaka/naechinso/domain/match/MatchService.java @@ -6,13 +6,21 @@ import com.tikitaka.naechinso.domain.match.constant.MatchStatus; import com.tikitaka.naechinso.domain.match.dto.*; import com.tikitaka.naechinso.domain.match.entity.Match; +import com.tikitaka.naechinso.domain.match.event.MatchLikeEvent; +import com.tikitaka.naechinso.domain.match.event.MatchOpenEvent; +import com.tikitaka.naechinso.domain.match.event.MatchResponseEvent; import com.tikitaka.naechinso.domain.member.MemberRepository; import com.tikitaka.naechinso.domain.member.entity.Member; import com.tikitaka.naechinso.global.error.ErrorCode; +import com.tikitaka.naechinso.global.error.exception.BadRequestException; import com.tikitaka.naechinso.global.error.exception.ForbiddenException; +import com.tikitaka.naechinso.global.error.exception.InternalServerException; import com.tikitaka.naechinso.global.error.exception.NotFoundException; +import lombok.Getter; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; +import org.apache.commons.lang3.StringUtils; +import org.springframework.context.ApplicationEventPublisher; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; @@ -28,6 +36,7 @@ public class MatchService { private final MemberRepository memberRepository; private final MatchRepository matchRepository; private final CardRepository cardRepository; + private final ApplicationEventPublisher applicationEventPublisher; /** * 활성화된 카드에 해당하는 상대에게 호감을 보낸다 @@ -53,21 +62,69 @@ public MatchResponseDTO like(Member authMember) { matchRepository.save(match); cardRepository.save(activeCard); + //알림 이벤트 전송 + try { + applicationEventPublisher.publishEvent(new MatchLikeEvent(authMember, targetMember)); + } catch (Exception e) { + log.error("푸시 알림 전송에 실패했습니다 - {}", e.getMessage()); + } + return MatchResponseDTO.of(match); } + /** + * 호감을 보낸 상대를 거절한다 + * @param authMember + * @return + */ + public MatchResponseDTO reject(Member authMember, Long matchId) { + Match match = matchRepository.findByIdAndToMemberAndStatus(matchId, authMember, MatchStatus.PENDING) + .orElseThrow(() -> new NotFoundException(ErrorCode.MATCH_NOT_FOUND)); + + Member fromMember = match.getFromMember(); + + match.reject(); + matchRepository.save(match); + + //알림 이벤트 전송 + if (fromMember.isAcceptsPush()) { + try { + MatchResponseEvent event = new MatchResponseEvent(fromMember, authMember, false); + applicationEventPublisher.publishEvent(event); + + } catch (Exception e) { + log.error("푸시 알림 전송에 실패했습니다 - {}", e.getMessage()); + } + } + + return MatchResponseDTO.of(match); + } /** - * 활성화된 카드에 해당하는 상대에게 호감을 보낸다 + * 호감을 보낸 상대를 수락한다 * @param authMember * @return */ public MatchResponseDTO accept(Member authMember, Long matchId) { - Match match = matchRepository.findByIdAndToMemberAndStatus(matchId, authMember,MatchStatus.PENDING) + Match match = matchRepository.findByIdAndToMemberAndStatus(matchId, authMember, MatchStatus.PENDING) .orElseThrow(() -> new NotFoundException(ErrorCode.MATCH_NOT_FOUND)); + Member fromMember = match.getFromMember(); + match.accept(); matchRepository.save(match); + + //알림 이벤트 전송 + if (fromMember.isAcceptsPush()) { + try { + MatchResponseEvent event = new MatchResponseEvent(fromMember, authMember, true); + applicationEventPublisher.publishEvent(event); + + } catch (Exception e) { + log.error("푸시 알림 전송에 실패했습니다 - {}", e.getMessage()); + } + } + return MatchResponseDTO.of(match); } @@ -89,6 +146,14 @@ public MatchResponseDTO openPhone(Member authMember, Long matchId) { match.open(); matchRepository.save(match); + //알림 이벤트 전송 + try { + Member opposite = authMember.equals(match.getFromMember()) ? match.getToMember() : match.getFromMember(); + applicationEventPublisher.publishEvent(new MatchOpenEvent(authMember, opposite)); + } catch (Exception e) { + log.error("푸시 알림 전송에 실패했습니다 - {}", e.getMessage()); + } + return MatchResponseDTO.of(match); } diff --git a/src/main/java/com/tikitaka/naechinso/domain/match/entity/Match.java b/src/main/java/com/tikitaka/naechinso/domain/match/entity/Match.java index 3f0f81c..5132d9d 100644 --- a/src/main/java/com/tikitaka/naechinso/domain/match/entity/Match.java +++ b/src/main/java/com/tikitaka/naechinso/domain/match/entity/Match.java @@ -39,6 +39,10 @@ public class Match extends BaseEntity { @JsonIgnore private Member toMember; + /* 호감 거절 */ + public void reject() { + this.status = MatchStatus.REJECTED; + } /* 서로 호감을 보내어 매칭 수락 */ public void accept() { this.status = MatchStatus.ACCEPTED; diff --git a/src/main/java/com/tikitaka/naechinso/domain/match/event/MatchLikeEvent.java b/src/main/java/com/tikitaka/naechinso/domain/match/event/MatchLikeEvent.java new file mode 100644 index 0000000..b80a0d2 --- /dev/null +++ b/src/main/java/com/tikitaka/naechinso/domain/match/event/MatchLikeEvent.java @@ -0,0 +1,12 @@ +package com.tikitaka.naechinso.domain.match.event; + +import com.tikitaka.naechinso.domain.member.entity.Member; +import lombok.Getter; +import lombok.RequiredArgsConstructor; + +@Getter +@RequiredArgsConstructor +public class MatchLikeEvent { + private final Member sender; + private final Member receiver; +} diff --git a/src/main/java/com/tikitaka/naechinso/domain/match/event/MatchOpenEvent.java b/src/main/java/com/tikitaka/naechinso/domain/match/event/MatchOpenEvent.java new file mode 100644 index 0000000..0410b5e --- /dev/null +++ b/src/main/java/com/tikitaka/naechinso/domain/match/event/MatchOpenEvent.java @@ -0,0 +1,12 @@ +package com.tikitaka.naechinso.domain.match.event; + +import com.tikitaka.naechinso.domain.member.entity.Member; +import lombok.Getter; +import lombok.RequiredArgsConstructor; + +@Getter +@RequiredArgsConstructor +public class MatchOpenEvent { + private final Member opener; + private final Member opposite; +} diff --git a/src/main/java/com/tikitaka/naechinso/domain/match/event/MatchResponseEvent.java b/src/main/java/com/tikitaka/naechinso/domain/match/event/MatchResponseEvent.java new file mode 100644 index 0000000..5d7a8c2 --- /dev/null +++ b/src/main/java/com/tikitaka/naechinso/domain/match/event/MatchResponseEvent.java @@ -0,0 +1,13 @@ +package com.tikitaka.naechinso.domain.match.event; + +import com.tikitaka.naechinso.domain.member.entity.Member; +import lombok.Getter; +import lombok.RequiredArgsConstructor; + +@Getter +@RequiredArgsConstructor +public class MatchResponseEvent { + private final Member sender; + private final Member receiver; + private final boolean isAccepted; +} diff --git a/src/main/java/com/tikitaka/naechinso/domain/member/entity/Member.java b/src/main/java/com/tikitaka/naechinso/domain/member/entity/Member.java index b410b03..9ba6b30 100644 --- a/src/main/java/com/tikitaka/naechinso/domain/member/entity/Member.java +++ b/src/main/java/com/tikitaka/naechinso/domain/member/entity/Member.java @@ -8,7 +8,6 @@ import com.tikitaka.naechinso.domain.member.dto.MemberUpdateCommonRequestDTO; import com.tikitaka.naechinso.domain.member.dto.MemberUpdateEduRequestDTO; import com.tikitaka.naechinso.domain.member.dto.MemberUpdateJobRequestDTO; -import com.tikitaka.naechinso.domain.notification.entity.Notification; import com.tikitaka.naechinso.domain.pending.entity.Pending; import com.tikitaka.naechinso.domain.point.constant.PointType; import com.tikitaka.naechinso.domain.point.entity.Point; @@ -34,7 +33,6 @@ @AllArgsConstructor @NoArgsConstructor @ToString -@EqualsAndHashCode public class Member extends BaseEntity { @Id @@ -80,6 +78,10 @@ public class Member extends BaseEntity { @Builder.Default private boolean acceptsMarketing = false; + @Column(name = "mem_accepts_push") + @Builder.Default + private boolean acceptsPush = true; + @Column(name = "mem_job_name") private String jobName; @@ -120,6 +122,10 @@ public class Member extends BaseEntity { @Builder.Default private Long point = 0L; + @Column(name = "mem_fcm_token") + @Builder.Default + private String fcmToken = ""; + //멤버 디테일 정보 @OneToOne(mappedBy = "member") @JoinColumn(name = "mem_detail") @@ -129,18 +135,20 @@ public class Member extends BaseEntity { @OneToMany(mappedBy = "member") @ToString.Exclude @JsonIgnore + @Builder.Default private List pending = new ArrayList<>(); //포인트 내역 @OneToMany(mappedBy = "member") + @ToString.Exclude @JsonIgnore + @Builder.Default private List points = new ArrayList<>(); - //내 가입 대기 정보 - @OneToMany(mappedBy = "member") - @ToString.Exclude - @JsonIgnore - private List notifications = new ArrayList<>(); +// @OneToMany(mappedBy = "member") +// @ToString.Exclude +// @JsonIgnore +// private List notifications = new ArrayList<>(); //내가 보낸 호감 내역 @OneToMany(mappedBy = "fromMember") @@ -161,18 +169,21 @@ public class Member extends BaseEntity { @OneToMany(mappedBy = "sender") @ToString.Exclude @JsonIgnore + @Builder.Default private List recommends = new ArrayList<>(); //나를 소개해준 사람들 @OneToMany(mappedBy = "receiver") @ToString.Exclude @JsonIgnore //순환참조 방지, 엔티티 프로퍼티 가려줌 + @Builder.Default private List recommendReceived = new ArrayList<>(); @OneToMany(mappedBy = "member", cascade = CascadeType.ALL) @ToString.Exclude @JsonIgnore - private List cards; + @Builder.Default + private List cards = new ArrayList<>(); public void setDetail(MemberDetail memberDetail) { diff --git a/src/main/java/com/tikitaka/naechinso/domain/notification/NotificationService.java b/src/main/java/com/tikitaka/naechinso/domain/notification/NotificationService.java deleted file mode 100644 index 57f5464..0000000 --- a/src/main/java/com/tikitaka/naechinso/domain/notification/NotificationService.java +++ /dev/null @@ -1,14 +0,0 @@ -package com.tikitaka.naechinso.domain.notification; - -import lombok.RequiredArgsConstructor; -import lombok.extern.slf4j.Slf4j; -import org.springframework.stereotype.Service; -import org.springframework.transaction.annotation.Transactional; - -@Slf4j -@Service -@RequiredArgsConstructor -@Transactional -public class NotificationService { - private final NotificationRepository notificationRepository; -} diff --git a/src/main/java/com/tikitaka/naechinso/global/config/async/AsyncConfig.java b/src/main/java/com/tikitaka/naechinso/global/config/async/AsyncConfig.java new file mode 100644 index 0000000..ef66932 --- /dev/null +++ b/src/main/java/com/tikitaka/naechinso/global/config/async/AsyncConfig.java @@ -0,0 +1,28 @@ +package com.tikitaka.naechinso.global.config.async; + +import lombok.extern.slf4j.Slf4j; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.scheduling.annotation.EnableAsync; +import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor; + +import java.util.concurrent.Executor; + +@Slf4j +@EnableAsync +@Configuration +public class AsyncConfig { + @Bean(name = "match") + public Executor threadPoolExecutor(){ + ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor(); + int processors = Runtime.getRuntime().availableProcessors(); + log.info("processors count {}",processors); + executor.setThreadNamePrefix("MatchingAsync-"); // thread 이름 설정 + executor.setCorePoolSize(processors); // 기본 스레드 수 + executor.setMaxPoolSize(processors*2); // 최대 스레드 개수 + executor.setQueueCapacity(50); // 최대 큐 수 + executor.setKeepAliveSeconds(60); // maxpool size로 인해 덤으로 더 돌아다니는 튜브는 60초 후에 수거해서 정리 + executor.initialize(); // 초기화후 반환 + return executor; + } +} diff --git a/src/main/java/com/tikitaka/naechinso/global/error/ErrorCode.java b/src/main/java/com/tikitaka/naechinso/global/error/ErrorCode.java index 5111aa7..a8e6236 100644 --- a/src/main/java/com/tikitaka/naechinso/global/error/ErrorCode.java +++ b/src/main/java/com/tikitaka/naechinso/global/error/ErrorCode.java @@ -15,16 +15,22 @@ public enum ErrorCode { _INTERNAL_SERVER_ERROR(INTERNAL_SERVER_ERROR, "C000", "서버 에러, 관리자에게 문의 바랍니다"), _BAD_REQUEST(BAD_REQUEST, "C001", "잘못된 요청입니다"), _UNAUTHORIZED(UNAUTHORIZED, "C002", "권한이 없습니다"), - _METHOD_NOT_ALLOWED(METHOD_NOT_ALLOWED, "C003", "지원하지 않는 Http Method 입니다"), _UNSUPPORTED_MEDIA_TYPE(UNSUPPORTED_MEDIA_TYPE, "C004", "지원하지 않는 Http Media PendingType 입니다"), _INVALID_REQUEST_PARAMETER(BAD_REQUEST, "C005", "유효하지 않은 Request Parameter 입니다"), CANNOT_CREATE_RECOMMEND(INTERNAL_SERVER_ERROR, "C006", "추천사 작성에 실패했습니다"), CANNOT_CREATE_RECOMMEND_REQUEST(INTERNAL_SERVER_ERROR, "C007", "추천사 요청에 실패했습니다"), - NOT_MULTIPART_HEADER(BAD_REQUEST, "C008", "Multipart 헤더가 아닙니다"), AMAZON_ACCESS_DENIED(FORBIDDEN, "C009", "Amazon S3 접근이 거부되었습니다"), + + /* DB 관련 오류 */ + CANNOT_CREATE_TUPLE(INTERNAL_SERVER_ERROR, "DB000", "새로운 인스턴스 생성을 실패했습니다"), + CANNOT_UPDATE_TUPLE(INTERNAL_SERVER_ERROR, "DB001", "인스턴스 업데이트에 실패했습니다"), + + /* 알림 관련 오류 */ + CANNOT_SEND_PUSH_NOTIFICATION(INTERNAL_SERVER_ERROR, "NOTICE000", "푸시 알림 전송에 실패했습니다"), + /* Auth 관련 오류 */ NO_TOKEN(UNAUTHORIZED, "AUTH000", "토큰이 존재하지 않습니다"), EXPIRED_TOKEN(UNAUTHORIZED, "AUTH001", "만료된 엑세스 토큰입니다"), diff --git a/src/main/java/com/tikitaka/naechinso/global/util/CustomStringUtil.java b/src/main/java/com/tikitaka/naechinso/global/util/CustomStringUtil.java index 75cf97c..4a1f308 100644 --- a/src/main/java/com/tikitaka/naechinso/global/util/CustomStringUtil.java +++ b/src/main/java/com/tikitaka/naechinso/global/util/CustomStringUtil.java @@ -2,7 +2,9 @@ public class CustomStringUtil { public static String hideName(String name) { - if (name.length() == 1) { + if (name == null) { + return null; + } else if (name.length() == 1) { return "*"; } else if (name.length() == 2) { return name.charAt(0) + "*"; diff --git a/src/main/java/com/tikitaka/naechinso/domain/notification/NotificationController.java b/src/main/java/com/tikitaka/naechinso/infra/notification/NotificationController.java similarity index 94% rename from src/main/java/com/tikitaka/naechinso/domain/notification/NotificationController.java rename to src/main/java/com/tikitaka/naechinso/infra/notification/NotificationController.java index 79628a7..1a61c43 100644 --- a/src/main/java/com/tikitaka/naechinso/domain/notification/NotificationController.java +++ b/src/main/java/com/tikitaka/naechinso/infra/notification/NotificationController.java @@ -1,4 +1,4 @@ -package com.tikitaka.naechinso.domain.notification; +package com.tikitaka.naechinso.infra.notification; import com.tikitaka.naechinso.domain.member.entity.Member; import com.tikitaka.naechinso.global.annotation.AuthMember; diff --git a/src/main/java/com/tikitaka/naechinso/domain/notification/NotificationRepository.java b/src/main/java/com/tikitaka/naechinso/infra/notification/NotificationRepository.java similarity index 54% rename from src/main/java/com/tikitaka/naechinso/domain/notification/NotificationRepository.java rename to src/main/java/com/tikitaka/naechinso/infra/notification/NotificationRepository.java index 6c2551a..a802f45 100644 --- a/src/main/java/com/tikitaka/naechinso/domain/notification/NotificationRepository.java +++ b/src/main/java/com/tikitaka/naechinso/infra/notification/NotificationRepository.java @@ -1,6 +1,6 @@ -package com.tikitaka.naechinso.domain.notification; +package com.tikitaka.naechinso.infra.notification; -import com.tikitaka.naechinso.domain.notification.entity.Notification; +import com.tikitaka.naechinso.infra.notification.entity.Notification; import org.springframework.data.jpa.repository.JpaRepository; public interface NotificationRepository extends JpaRepository { diff --git a/src/main/java/com/tikitaka/naechinso/infra/notification/NotificationService.java b/src/main/java/com/tikitaka/naechinso/infra/notification/NotificationService.java new file mode 100644 index 0000000..1a8e2a4 --- /dev/null +++ b/src/main/java/com/tikitaka/naechinso/infra/notification/NotificationService.java @@ -0,0 +1,140 @@ +package com.tikitaka.naechinso.infra.notification; + +import com.google.auth.oauth2.GoogleCredentials; +import com.google.firebase.FirebaseApp; +import com.google.firebase.FirebaseOptions; +import com.google.firebase.messaging.*; +import com.tikitaka.naechinso.global.error.ErrorCode; +import com.tikitaka.naechinso.global.error.exception.InternalServerException; +import com.tikitaka.naechinso.infra.notification.constant.NotificationType; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.core.io.ClassPathResource; +import org.springframework.lang.Nullable; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +import javax.annotation.PostConstruct; +import java.io.IOException; +import java.time.LocalDateTime; +import java.util.*; +import java.util.stream.Collectors; + +@Slf4j +@Service +@RequiredArgsConstructor +@Transactional +public class NotificationService { + private final NotificationRepository notificationRepository; + + @Value("${fcm.key.path}") + private String FCM_PRIVATE_KEY_PATH; + + // + // 메시징만 권한 설정 + @Value("${fcm.key.scope}") + private String fireBaseScope; + + // fcm 기본 설정 진행 + @PostConstruct + public void init() { + try { + FirebaseOptions options = new FirebaseOptions.Builder() + .setCredentials( + GoogleCredentials + .fromStream(new ClassPathResource(FCM_PRIVATE_KEY_PATH).getInputStream()) + .createScoped(List.of(fireBaseScope))) + .build(); + if (FirebaseApp.getApps().isEmpty()) { + FirebaseApp.initializeApp(options); + log.info("Firebase application has been initialized"); + } + } catch (IOException e) { + log.error(e.getMessage()); + // spring 뜰때 알림 서버가 잘 동작하지 않는 것이므로 바로 죽임 + throw new RuntimeException(e.getMessage()); + } + } + + public void sendByToken(String token, String title, String content) { + + // 메시지 만들기 + Message message = Message.builder() + .putData("time", LocalDateTime.now().toString()) + .setNotification(new Notification(title, content)) + .setToken(token) + .build(); + + try { + // 알림 발송 + FirebaseMessaging.getInstance().send(message); + } catch (FirebaseMessagingException e) { + log.error("cannot send to memberList push message. error info : {}", e.getMessage()); + } + } + + // 알림 보내기 + public void sendByTokenList(List tokenList, String title, String content) { + + // 메시지 만들기 + List messages = tokenList.stream().map(token -> Message.builder() + .putData("time", LocalDateTime.now().toString()) + .setNotification(new Notification(title, content)) + .setToken(token) + .build()).collect(Collectors.toList()); + + // 요청에 대한 응답을 받을 response + BatchResponse response; + try { + + // 알림 발송 + response = FirebaseMessaging.getInstance().sendAll(messages); + + // 요청에 대한 응답 처리 + if (response.getFailureCount() > 0) { + List responses = response.getResponses(); + List failedTokens = new ArrayList<>(); + + // response 내부에 error 가 포함되어 있음 (Exception 발생 x) + for (int i = 0; i < responses.size(); i++) { + if (!responses.get(i).isSuccessful()) { + failedTokens.add(tokenList.get(i)); + } + } + log.error("List of tokens are not valid FCM token : " + failedTokens); + } + } catch (FirebaseMessagingException e) { + log.error("cannot send to memberList push message. error info : {}", e.getMessage()); + } + } + + public void createNotification(Long memberId, String title, String content, NotificationType notificationType) { + try { + notificationRepository.save( + com.tikitaka.naechinso.infra.notification.entity.Notification.builder() + .title(title) + .content(content) + .memberId(memberId) + .type(notificationType) + .build()); + } catch (Exception e) { + throw new InternalServerException(ErrorCode.CANNOT_CREATE_TUPLE); + } + } + + public void createNotificationList(List memberId, String title, String content, NotificationType notificationType) { + try { + notificationRepository.saveAll(memberId.stream().map(id -> + com.tikitaka.naechinso.infra.notification.entity.Notification.builder() + .title(title) + .content(content) + .memberId(id) + .type(notificationType) + .build() + ).collect(Collectors.toList())); + } catch (Exception e) { + throw new InternalServerException(ErrorCode.CANNOT_CREATE_TUPLE); + } + } +} diff --git a/src/main/java/com/tikitaka/naechinso/domain/notification/constant/NotificationType.java b/src/main/java/com/tikitaka/naechinso/infra/notification/constant/NotificationType.java similarity index 85% rename from src/main/java/com/tikitaka/naechinso/domain/notification/constant/NotificationType.java rename to src/main/java/com/tikitaka/naechinso/infra/notification/constant/NotificationType.java index 2129fde..dcabdd7 100644 --- a/src/main/java/com/tikitaka/naechinso/domain/notification/constant/NotificationType.java +++ b/src/main/java/com/tikitaka/naechinso/infra/notification/constant/NotificationType.java @@ -1,11 +1,11 @@ -package com.tikitaka.naechinso.domain.notification.constant; +package com.tikitaka.naechinso.infra.notification.constant; import com.fasterxml.jackson.annotation.JsonCreator; public enum NotificationType { ALARM, - //매칭 알람 + //호감 및 매칭 알람 MATCH, //마케팅 메세지 @@ -13,6 +13,7 @@ public enum NotificationType { ; + //Enum Validation 을 위한 코드, enum 에 속하지 않으면 null 리턴 @JsonCreator public static NotificationType fromNotificationType(String val){ diff --git a/src/main/java/com/tikitaka/naechinso/domain/notification/dto/NotificationHistoryResponseDTO.java b/src/main/java/com/tikitaka/naechinso/infra/notification/dto/NotificationHistoryResponseDTO.java similarity index 80% rename from src/main/java/com/tikitaka/naechinso/domain/notification/dto/NotificationHistoryResponseDTO.java rename to src/main/java/com/tikitaka/naechinso/infra/notification/dto/NotificationHistoryResponseDTO.java index 659554d..41cf9c0 100644 --- a/src/main/java/com/tikitaka/naechinso/domain/notification/dto/NotificationHistoryResponseDTO.java +++ b/src/main/java/com/tikitaka/naechinso/infra/notification/dto/NotificationHistoryResponseDTO.java @@ -1,8 +1,7 @@ -package com.tikitaka.naechinso.domain.notification.dto; +package com.tikitaka.naechinso.infra.notification.dto; -import com.tikitaka.naechinso.domain.notification.constant.NotificationType; -import com.tikitaka.naechinso.domain.notification.entity.Notification; -import com.tikitaka.naechinso.domain.point.dto.PointHistoryResponseDTO; +import com.tikitaka.naechinso.infra.notification.constant.NotificationType; +import com.tikitaka.naechinso.infra.notification.entity.Notification; import lombok.*; import java.util.ArrayList; diff --git a/src/main/java/com/tikitaka/naechinso/domain/notification/entity/Notification.java b/src/main/java/com/tikitaka/naechinso/infra/notification/entity/Notification.java similarity index 66% rename from src/main/java/com/tikitaka/naechinso/domain/notification/entity/Notification.java rename to src/main/java/com/tikitaka/naechinso/infra/notification/entity/Notification.java index 660ccd5..3306118 100644 --- a/src/main/java/com/tikitaka/naechinso/domain/notification/entity/Notification.java +++ b/src/main/java/com/tikitaka/naechinso/infra/notification/entity/Notification.java @@ -1,8 +1,8 @@ -package com.tikitaka.naechinso.domain.notification.entity; +package com.tikitaka.naechinso.infra.notification.entity; import com.fasterxml.jackson.annotation.JsonIgnore; import com.tikitaka.naechinso.domain.member.entity.Member; -import com.tikitaka.naechinso.domain.notification.constant.NotificationType; +import com.tikitaka.naechinso.infra.notification.constant.NotificationType; import com.tikitaka.naechinso.global.config.entity.BaseEntity; import lombok.*; @@ -21,11 +21,13 @@ public class Notification extends BaseEntity { @GeneratedValue private Long id; - /* 알림 주인 */ - @ManyToOne(fetch = FetchType.LAZY) - @JoinColumn(name = "mem_id") - @JsonIgnore - private Member member; +// /* 알림 주인 */ +// @ManyToOne(fetch = FetchType.LAZY) +// @JoinColumn(name = "mem_id") +// @JsonIgnore +// private Member member; + @Column(name = "mem_id") + private Long memberId; @Column(name = "not_type") @Enumerated(EnumType.STRING) diff --git a/src/main/resources/application.yml b/src/main/resources/application.yml index 16b3960..7892517 100644 --- a/src/main/resources/application.yml +++ b/src/main/resources/application.yml @@ -28,6 +28,11 @@ spring: swagger: use-model-v3: false +fcm: + key: + path: naechinso-fcm.json + scope: https://www.googleapis.com/auth/cloud-platform + logging.level: org.hibernate.SQL: debug org.hibernate.type: trace From 885c60cad3856a275c7d3faef1a14cb87ef2aba8 Mon Sep 17 00:00:00 2001 From: gengminy Date: Sun, 30 Oct 2022 16:03:40 +0900 Subject: [PATCH 46/72] =?UTF-8?q?:rocket:=20feat(notify):=20=EB=A9=A4?= =?UTF-8?q?=EB=B2=84=20=ED=91=B8=EC=8B=9C=20=EC=95=8C=EB=A6=BC=20=ED=86=A0?= =?UTF-8?q?=ED=81=B0=20=EB=93=B1=EB=A1=9D=20=EA=B8=B0=EB=8A=A5=20=EC=B6=94?= =?UTF-8?q?=EA=B0=80=20#50?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../domain/member/MemberController.java | 26 ++++++ .../domain/member/MemberService.java | 89 ++++++++++++------- .../member/dto/MemberLoginRequestDTO.java | 17 ++++ .../member/dto/MemberLoginResponseDTO.java | 12 +++ .../domain/member/entity/Member.java | 3 +- .../naechinso/global/error/ErrorCode.java | 2 + 6 files changed, 118 insertions(+), 31 deletions(-) create mode 100644 src/main/java/com/tikitaka/naechinso/domain/member/dto/MemberLoginRequestDTO.java create mode 100644 src/main/java/com/tikitaka/naechinso/domain/member/dto/MemberLoginResponseDTO.java diff --git a/src/main/java/com/tikitaka/naechinso/domain/member/MemberController.java b/src/main/java/com/tikitaka/naechinso/domain/member/MemberController.java index 364303b..b36f604 100644 --- a/src/main/java/com/tikitaka/naechinso/domain/member/MemberController.java +++ b/src/main/java/com/tikitaka/naechinso/domain/member/MemberController.java @@ -62,6 +62,32 @@ public CommonApiResponse getMemberDetail( return CommonApiResponse.of(res); } + @PostMapping("/login") + @ApiOperation(value = "FCM Token 을 등록하여 로그인 처리를 진행한다 (AccessToken)") + public CommonApiResponse login( + @Valid @RequestBody MemberLoginRequestDTO requestDTO, + @ApiIgnore @AuthMember Member member + ) { + return CommonApiResponse.of(memberService.login(member, requestDTO)); + } + + @PostMapping("/login/force") + @ApiOperation(value = "FCM Token 을 교체한다 (AccessToken)") + public CommonApiResponse forceLogin( + @Valid @RequestBody MemberLoginRequestDTO requestDTO, + @ApiIgnore @AuthMember Member member + ) { + return CommonApiResponse.of(memberService.forceLogin(member, requestDTO)); + } + + @PostMapping("/logout") + @ApiOperation(value = "FCM Token 을 삭제하여 로그아웃 처리한다 (AccessToken)") + public CommonApiResponse logout( + @ApiIgnore @AuthMember Member member + ) { + return CommonApiResponse.of(memberService.logout(member)); + } + @PostMapping("/join") @ApiOperation(value = "유저를 공통 정보로 가입시킨다 (RegisterToken)") public CommonApiResponse createCommonMember( diff --git a/src/main/java/com/tikitaka/naechinso/domain/member/MemberService.java b/src/main/java/com/tikitaka/naechinso/domain/member/MemberService.java index d7f77c9..c3d0409 100644 --- a/src/main/java/com/tikitaka/naechinso/domain/member/MemberService.java +++ b/src/main/java/com/tikitaka/naechinso/domain/member/MemberService.java @@ -20,6 +20,7 @@ import com.tikitaka.naechinso.global.error.exception.NotFoundException; import com.tikitaka.naechinso.global.error.exception.UnauthorizedException; import lombok.RequiredArgsConstructor; +import org.apache.commons.lang3.StringUtils; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; @@ -30,32 +31,58 @@ @RequiredArgsConstructor @Transactional public class MemberService { - private final JwtTokenProvider jwtTokenProvider; private final PendingService pendingService; - private final CardService cardService; private final MemberRepository memberRepository; private final MemberDetailRepository memberDetailRepository; - public Member findByPhone(String phone) { - return memberRepository.findByPhone(phone) - .orElseThrow(() -> new NotFoundException(ErrorCode.USER_NOT_FOUND)); - } + /** + * 로그인 -> Fcm Token DB에 등록한다 + * */ + public MemberLoginResponseDTO login(Member authMember, MemberLoginRequestDTO requestDTO) { + Member member = findByMember(authMember); - public Member findByMember(Member member) { - return findByPhone(member.getPhone()); + //이미 로그인 된 상태 + if (!StringUtils.isBlank(member.getFcmToken())) { + throw new BadRequestException(ErrorCode.USER_ALREADY_LOGGED_IN); + } + + member.setFcmToken(requestDTO.getFcmToken()); + memberRepository.save(member); + + return new MemberLoginResponseDTO(requestDTO.getFcmToken()); } - public List findAll() { - return memberRepository.findAll().stream() - .map(MemberFindResponseDTO::of).collect(Collectors.toList()); + /** + * 강제 로그인 -> Fcm Token 을 교체한다 + * */ + public MemberLoginResponseDTO forceLogin(Member authMember, MemberLoginRequestDTO requestDTO) { + Member member = findByMember(authMember); + + member.setFcmToken(requestDTO.getFcmToken()); + memberRepository.save(member); + + return new MemberLoginResponseDTO(requestDTO.getFcmToken()); } - public MemberCommonResponseDTO readCommonMember(Member authMember) { + /** + * 로그아웃 -> Fcm Token DB에서 삭제한다 + * */ + public MemberLoginResponseDTO logout(Member authMember) { Member member = findByMember(authMember); - return MemberCommonResponseDTO.of(member); + + //이미 로그아웃 된 상태 + if (StringUtils.isBlank(member.getFcmToken())) { + throw new BadRequestException(ErrorCode.USER_ALREADY_LOGGED_OUT); + } + + member.setFcmToken(""); + memberRepository.save(member); + + return new MemberLoginResponseDTO(""); } + public MemberCommonJoinResponseDTO joinCommonMember(String phone, MemberCommonJoinRequestDTO dto) { //이미 존재하는 유저일 경우 400 Optional checkMember = memberRepository.findByPhone(phone); @@ -91,23 +118,6 @@ public MemberDetailResponseDTO readDetail(Member member) { return MemberDetailResponseDTO.of(member); } - -// /** -// * 랜덤 추천받은 상대의 프로필 카드를 가져오는 서비스 로직 -// * ACTIVE 한 카드에만 접근 권한이 있음 -// * */ -// public MemberOppositeProfileResponseDTO readOppositeMemberDetailAndRecommendById(Member authMember, Long id) { -// //현재 ACTIVE 한 카드와 요청 id가 같지 않으면 에러 -// Card activeCard = cardService.findByMemberAndIsActiveTrue(authMember); -// Long targetId = activeCard.getTargetMemberId(); -// if (!targetId.equals(id)) { -// throw new ForbiddenException(ErrorCode.FORBIDDEN_PROFILE); -// } -// -// Member oppositeMember = findById(targetId); -// return MemberOppositeProfileResponseDTO.of(oppositeMember); -// } - public MemberDetailResponseDTO createDetail(Member authMember, MemberDetailJoinRequestDTO dto) { //영속성 유지를 위한 fetch Member member = findByMember(authMember); @@ -205,4 +215,23 @@ public boolean existsById(Long memberId) { return memberRepository.existsById(memberId); } + + public Member findByPhone(String phone) { + return memberRepository.findByPhone(phone) + .orElseThrow(() -> new NotFoundException(ErrorCode.USER_NOT_FOUND)); + } + + public Member findByMember(Member member) { + return findByPhone(member.getPhone()); + } + + public List findAll() { + return memberRepository.findAll().stream() + .map(MemberFindResponseDTO::of).collect(Collectors.toList()); + } + + public MemberCommonResponseDTO readCommonMember(Member authMember) { + Member member = findByMember(authMember); + return MemberCommonResponseDTO.of(member); + } } diff --git a/src/main/java/com/tikitaka/naechinso/domain/member/dto/MemberLoginRequestDTO.java b/src/main/java/com/tikitaka/naechinso/domain/member/dto/MemberLoginRequestDTO.java new file mode 100644 index 0000000..a489d43 --- /dev/null +++ b/src/main/java/com/tikitaka/naechinso/domain/member/dto/MemberLoginRequestDTO.java @@ -0,0 +1,17 @@ +package com.tikitaka.naechinso.domain.member.dto; + +import io.swagger.annotations.ApiModelProperty; +import lombok.*; + +import javax.validation.constraints.NotBlank; + +@AllArgsConstructor +@NoArgsConstructor +@Getter +@Builder +@ToString +public class MemberLoginRequestDTO { + @ApiModelProperty(example = "asdsad") + @NotBlank(message = "FCM Token 정보를 입력해야 합니다") + private String fcmToken; +} diff --git a/src/main/java/com/tikitaka/naechinso/domain/member/dto/MemberLoginResponseDTO.java b/src/main/java/com/tikitaka/naechinso/domain/member/dto/MemberLoginResponseDTO.java new file mode 100644 index 0000000..5b8003d --- /dev/null +++ b/src/main/java/com/tikitaka/naechinso/domain/member/dto/MemberLoginResponseDTO.java @@ -0,0 +1,12 @@ +package com.tikitaka.naechinso.domain.member.dto; + +import lombok.*; + +@AllArgsConstructor +@NoArgsConstructor +@Getter +@Builder +@ToString +public class MemberLoginResponseDTO { + private String fcmToken; +} diff --git a/src/main/java/com/tikitaka/naechinso/domain/member/entity/Member.java b/src/main/java/com/tikitaka/naechinso/domain/member/entity/Member.java index 9ba6b30..b5eae7c 100644 --- a/src/main/java/com/tikitaka/naechinso/domain/member/entity/Member.java +++ b/src/main/java/com/tikitaka/naechinso/domain/member/entity/Member.java @@ -260,7 +260,8 @@ public void acceptEduImage() { this.eduAccepted = true; } - + public void setFcmToken(String token) { this.fcmToken = token; } + public void deleteFcmToken() { this.fcmToken = ""; } diff --git a/src/main/java/com/tikitaka/naechinso/global/error/ErrorCode.java b/src/main/java/com/tikitaka/naechinso/global/error/ErrorCode.java index a8e6236..053db26 100644 --- a/src/main/java/com/tikitaka/naechinso/global/error/ErrorCode.java +++ b/src/main/java/com/tikitaka/naechinso/global/error/ErrorCode.java @@ -58,6 +58,8 @@ public enum ErrorCode { RANDOM_USER_NOT_FOUND(NOT_FOUND, "U006","추천할 수 있는 유저가 더 이상 없습니다"), FORBIDDEN_PROFILE(FORBIDDEN, "U007","해당 유저 프로필에 대한 접근 권한이 없습니다"), USER_NOT_SIGNED_UP(NOT_FOUND, "U008","정회원으로 가입된 유저가 아닙니다"), + USER_ALREADY_LOGGED_IN(BAD_REQUEST, "U009","이미 로그인 상태입니다"), + USER_ALREADY_LOGGED_OUT(BAD_REQUEST, "U010","이미 로그아웃 상태입니다"), /* Recommend 관련 오류 */ From 8b1bd2267ab52d68debbbcebb4147e07e91cd531 Mon Sep 17 00:00:00 2001 From: gengminy Date: Sun, 30 Oct 2022 16:30:56 +0900 Subject: [PATCH 47/72] =?UTF-8?q?:rocket:=20feat(notify):=20=EC=9C=A0?= =?UTF-8?q?=EC=A0=80=20=ED=91=B8=EC=8B=9C=EC=95=8C=EB=A6=BC=20=EC=88=98?= =?UTF-8?q?=EC=8B=A0=20=EC=97=AC=EB=B6=80=20=EB=B3=80=EA=B2=BD=20=EC=B6=94?= =?UTF-8?q?=EA=B0=80=20#50?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../domain/member/MemberController.java | 9 +++++ .../domain/member/MemberService.java | 10 ++++++ .../member/dto/MemberAcceptsResponseDTO.java | 36 +++++++++++++++++++ .../dto/MemberUpdateAcceptsRequestDTO.java | 29 +++++++++++++++ .../domain/member/entity/Member.java | 7 ++++ 5 files changed, 91 insertions(+) create mode 100644 src/main/java/com/tikitaka/naechinso/domain/member/dto/MemberAcceptsResponseDTO.java create mode 100644 src/main/java/com/tikitaka/naechinso/domain/member/dto/MemberUpdateAcceptsRequestDTO.java diff --git a/src/main/java/com/tikitaka/naechinso/domain/member/MemberController.java b/src/main/java/com/tikitaka/naechinso/domain/member/MemberController.java index b36f604..df81f59 100644 --- a/src/main/java/com/tikitaka/naechinso/domain/member/MemberController.java +++ b/src/main/java/com/tikitaka/naechinso/domain/member/MemberController.java @@ -144,6 +144,15 @@ public CommonApiResponse updateImage( return CommonApiResponse.of(memberService.updateImage(member, dto)); } + @PatchMapping("/accept") + @ApiOperation(value = "동의 정보 여부를 업데이트 한다 (AccessToken)") + public CommonApiResponse updateAccepts( + @Valid @RequestBody MemberUpdateAcceptsRequestDTO dto, + @ApiIgnore @AuthMember Member member + ) { + return CommonApiResponse.of(memberService.updateAccepts(member, dto)); + } + //페이징 처리 추가할 예정 @GetMapping("/find") diff --git a/src/main/java/com/tikitaka/naechinso/domain/member/MemberService.java b/src/main/java/com/tikitaka/naechinso/domain/member/MemberService.java index c3d0409..74766e8 100644 --- a/src/main/java/com/tikitaka/naechinso/domain/member/MemberService.java +++ b/src/main/java/com/tikitaka/naechinso/domain/member/MemberService.java @@ -175,6 +175,16 @@ public MemberCommonResponseDTO updateEduRequest(Member authMember, MemberUpdateE return pendingService.createPendingByEdu(authMember, dto); } + /** + * 동의 정보 여부를 수정한다 + * */ + public MemberAcceptsResponseDTO updateAccepts(Member authMember, MemberUpdateAcceptsRequestDTO dto){ + Member member = findByMember(authMember); + member.updateAccepts(dto); + memberRepository.save(member); + return MemberAcceptsResponseDTO.of(member); + } + /** * MemberDetail 의 프로필 이미지를 업로드 한다 * */ diff --git a/src/main/java/com/tikitaka/naechinso/domain/member/dto/MemberAcceptsResponseDTO.java b/src/main/java/com/tikitaka/naechinso/domain/member/dto/MemberAcceptsResponseDTO.java new file mode 100644 index 0000000..90cc305 --- /dev/null +++ b/src/main/java/com/tikitaka/naechinso/domain/member/dto/MemberAcceptsResponseDTO.java @@ -0,0 +1,36 @@ +package com.tikitaka.naechinso.domain.member.dto; + +import com.tikitaka.naechinso.domain.member.entity.Member; +import lombok.*; + +import javax.validation.constraints.AssertTrue; +import javax.validation.constraints.NotNull; + +/** + * 동의 여부에 대한 응답 DTO + * @author gengminy 221030 + * */ +@AllArgsConstructor +@NoArgsConstructor +@Getter +@Builder +@ToString +public class MemberAcceptsResponseDTO { + private boolean acceptsService; + private boolean acceptsInfo; + private boolean acceptsReligion; + private boolean acceptsLocation; + private boolean acceptsMarketing; + private boolean acceptsPush; + + public static MemberAcceptsResponseDTO of(Member member){ + return MemberAcceptsResponseDTO.builder() + .acceptsInfo(member.isAcceptsInfo()) + .acceptsLocation(member.isAcceptsLocation()) + .acceptsMarketing(member.isAcceptsMarketing()) + .acceptsReligion(member.isAcceptsReligion()) + .acceptsPush(member.isAcceptsPush()) + .acceptsService(member.isAcceptsService()) + .build(); + } +} diff --git a/src/main/java/com/tikitaka/naechinso/domain/member/dto/MemberUpdateAcceptsRequestDTO.java b/src/main/java/com/tikitaka/naechinso/domain/member/dto/MemberUpdateAcceptsRequestDTO.java new file mode 100644 index 0000000..e6c1de7 --- /dev/null +++ b/src/main/java/com/tikitaka/naechinso/domain/member/dto/MemberUpdateAcceptsRequestDTO.java @@ -0,0 +1,29 @@ +package com.tikitaka.naechinso.domain.member.dto; + +import io.swagger.annotations.ApiModelProperty; +import lombok.*; + +import javax.validation.constraints.AssertTrue; +import javax.validation.constraints.NotNull; +import javax.validation.constraints.Size; +import java.util.List; + +/** + * 직업 정보 업데이트를 위한 DTO + * @author gengminy 221005 + * */ +@AllArgsConstructor +@NoArgsConstructor +@Getter +@Builder +@ToString +public class MemberUpdateAcceptsRequestDTO { + @NotNull(message = "위치 정보 제공 동의 여부가 필요합니다") + private boolean acceptsLocation; + + @NotNull(message = "마케팅 동의 여부가 필요합니다") + private boolean acceptsMarketing; + + @NotNull(message = "푸시 알림 동의 여부가 필요합니다") + private boolean acceptsPush; +} diff --git a/src/main/java/com/tikitaka/naechinso/domain/member/entity/Member.java b/src/main/java/com/tikitaka/naechinso/domain/member/entity/Member.java index b5eae7c..8fa7d61 100644 --- a/src/main/java/com/tikitaka/naechinso/domain/member/entity/Member.java +++ b/src/main/java/com/tikitaka/naechinso/domain/member/entity/Member.java @@ -5,6 +5,7 @@ import com.tikitaka.naechinso.domain.match.entity.Match; import com.tikitaka.naechinso.domain.member.constant.Gender; import com.tikitaka.naechinso.domain.member.constant.Role; +import com.tikitaka.naechinso.domain.member.dto.MemberUpdateAcceptsRequestDTO; import com.tikitaka.naechinso.domain.member.dto.MemberUpdateCommonRequestDTO; import com.tikitaka.naechinso.domain.member.dto.MemberUpdateEduRequestDTO; import com.tikitaka.naechinso.domain.member.dto.MemberUpdateJobRequestDTO; @@ -190,6 +191,12 @@ public void setDetail(MemberDetail memberDetail) { this.detail = memberDetail; } + public void updateAccepts(MemberUpdateAcceptsRequestDTO requestDTO) { + this.acceptsMarketing = requestDTO.isAcceptsMarketing(); + this.acceptsPush = requestDTO.isAcceptsPush(); + this.acceptsLocation = requestDTO.isAcceptsLocation(); + } + public void updateJob(MemberUpdateJobRequestDTO requestDTO) { this.jobName = requestDTO.getJobName(); this.jobLocation = requestDTO.getJobLocation(); From a69025241e7ba56597e35199f41b159f5e099808 Mon Sep 17 00:00:00 2001 From: gengminy Date: Sun, 30 Oct 2022 20:29:24 +0900 Subject: [PATCH 48/72] =?UTF-8?q?:hammer:=20fix(card):=20=EB=82=B4=20?= =?UTF-8?q?=EC=B9=B4=EB=93=9C=20=EA=B0=80=EC=A0=B8=EC=98=A4=EA=B8=B0=20?= =?UTF-8?q?=EB=B0=98=ED=99=98=EA=B0=92=20=EB=B3=80=EA=B2=BD=20#41?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../naechinso/domain/card/CardController.java | 4 +-- .../naechinso/domain/card/CardService.java | 22 ++++++++------- .../CardOppositeMemberProfileResponseDTO.java | 4 +-- .../domain/member/MemberController.java | 8 ++++++ .../domain/member/MemberService.java | 18 ++++++++++--- .../domain/member/entity/Member.java | 7 ++++- .../domain/member/entity/MemberDetail.java | 8 ++---- .../naechinso/domain/point/entity/Point.java | 2 -- .../global/config/entity/BaseEntity.java | 27 +++++++++++-------- .../global/config/entity/BaseTimeEntity.java | 26 ------------------ 10 files changed, 63 insertions(+), 63 deletions(-) delete mode 100644 src/main/java/com/tikitaka/naechinso/global/config/entity/BaseTimeEntity.java diff --git a/src/main/java/com/tikitaka/naechinso/domain/card/CardController.java b/src/main/java/com/tikitaka/naechinso/domain/card/CardController.java index bcc6d7f..ede0aca 100644 --- a/src/main/java/com/tikitaka/naechinso/domain/card/CardController.java +++ b/src/main/java/com/tikitaka/naechinso/domain/card/CardController.java @@ -23,8 +23,8 @@ public class CardController { private final CardService cardService; @GetMapping - @ApiOperation(value = "자신이 소유한 모든 카드를 가져온다 (AccessToken)") - public CommonApiResponse> getAllCardsByMember( + @ApiOperation(value = "자신이 소유한 모든 카드 썸네일을 가져온다 (AccessToken)") + public CommonApiResponse> getAllCardsByMember( @ApiIgnore @AuthMember Member member ) { return CommonApiResponse.of(cardService.findAllCard(member)); diff --git a/src/main/java/com/tikitaka/naechinso/domain/card/CardService.java b/src/main/java/com/tikitaka/naechinso/domain/card/CardService.java index 9f35d48..546102f 100644 --- a/src/main/java/com/tikitaka/naechinso/domain/card/CardService.java +++ b/src/main/java/com/tikitaka/naechinso/domain/card/CardService.java @@ -10,20 +10,15 @@ import com.tikitaka.naechinso.domain.member.entity.Member; import com.tikitaka.naechinso.global.error.ErrorCode; import com.tikitaka.naechinso.global.error.exception.BadRequestException; -import com.tikitaka.naechinso.global.error.exception.ForbiddenException; import com.tikitaka.naechinso.global.error.exception.NotFoundException; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; -import org.springframework.http.ResponseEntity; import org.springframework.stereotype.Service; -import org.springframework.web.bind.annotation.ResponseBody; import java.time.LocalDate; import java.time.LocalDateTime; import java.time.LocalTime; -import java.util.HashMap; import java.util.List; -import java.util.Map; import java.util.Random; import java.util.stream.Collectors; @@ -37,10 +32,20 @@ public class CardService { /** - * 내가 받았던 모든 카드 기록을 가져온다 (챗봇 썸네일) + * 내가 받았던 모든 카드 기록을 가져온다 (챗봇 썸네일용) */ - public List findAllCard(Member authMember){ - return cardRepository.findAllDTOByMember(authMember); + public List findAllCard(Member authMember){ + return cardRepository.findAllByMember(authMember).stream().map( + card -> { + Member targetMember = memberRepository.findById(card.getTargetMemberId()) + .orElse(null); + + if (targetMember == null) { + return null; + } + return CardOppositeMemberProfileResponseDTO.of(targetMember); + } + ).collect(Collectors.toList()); } /** @@ -54,7 +59,6 @@ public CardCountResponseDTO getRemainingCount(Member authMember) { else return new CardCountResponseDTO(count); } - /** * 추천 받았던 유저를 필터링한 랜덤 추천 카드를 만든다 * */ diff --git a/src/main/java/com/tikitaka/naechinso/domain/card/dto/CardOppositeMemberProfileResponseDTO.java b/src/main/java/com/tikitaka/naechinso/domain/card/dto/CardOppositeMemberProfileResponseDTO.java index d6730f6..234582c 100644 --- a/src/main/java/com/tikitaka/naechinso/domain/card/dto/CardOppositeMemberProfileResponseDTO.java +++ b/src/main/java/com/tikitaka/naechinso/domain/card/dto/CardOppositeMemberProfileResponseDTO.java @@ -67,9 +67,9 @@ public static class Recommendation { private String period; private String appealDetail; - public static CardOppositeMemberProfileResponseDTO.Recommendation of(Recommend recommend) { + public static Recommendation of(Recommend recommend) { Member sender = recommend.getSender(); - return CardOppositeMemberProfileResponseDTO.Recommendation.builder() + return Recommendation.builder() .name(CustomStringUtil.hideName(recommend.getSenderName())) .gender(recommend.getSenderGender()) .appeal(recommend.getReceiverAppeal()) diff --git a/src/main/java/com/tikitaka/naechinso/domain/member/MemberController.java b/src/main/java/com/tikitaka/naechinso/domain/member/MemberController.java index df81f59..8a55962 100644 --- a/src/main/java/com/tikitaka/naechinso/domain/member/MemberController.java +++ b/src/main/java/com/tikitaka/naechinso/domain/member/MemberController.java @@ -88,6 +88,14 @@ public CommonApiResponse logout( return CommonApiResponse.of(memberService.logout(member)); } + @DeleteMapping("/delete") + @ApiOperation(value = "회원 탈퇴 처리한다 (soft delete) (AccessToken)") + public CommonApiResponse delete( + @ApiIgnore @AuthMember Member member + ) { + return CommonApiResponse.of(memberService.delete(member)); + } + @PostMapping("/join") @ApiOperation(value = "유저를 공통 정보로 가입시킨다 (RegisterToken)") public CommonApiResponse createCommonMember( diff --git a/src/main/java/com/tikitaka/naechinso/domain/member/MemberService.java b/src/main/java/com/tikitaka/naechinso/domain/member/MemberService.java index 74766e8..d3a22d7 100644 --- a/src/main/java/com/tikitaka/naechinso/domain/member/MemberService.java +++ b/src/main/java/com/tikitaka/naechinso/domain/member/MemberService.java @@ -158,11 +158,7 @@ public MemberDetailResponseDTO createDetail(Member authMember, MemberDetailJoinR * 사진 필드는 Pending 에서 승인 후 처리한다 * */ public MemberCommonResponseDTO updateJobRequest(Member authMember, MemberUpdateJobRequestDTO dto){ -// member.updateJob(dto); -// memberRepository.save(member); - //직업 정보 승인 요청 - return pendingService.createPendingByJob(authMember, dto); } @@ -192,6 +188,20 @@ public MemberDetailResponseDTO updateImage(Member authMember, MemberUpdateImageR return pendingService.createPendingByMemberImage(authMember, dto); } + /** + * MemberDetail 의 프로필 이미지를 업로드 한다 + * */ + public Member delete(Member authMember){ + Member member = findByMember(authMember); + + memberRepository.delete(authMember); + + System.out.println("member.getCreatedAt() = " + member.getCreatedAt()); + System.out.println("member.getUpdatedAt() = " + member.getUpdatedAt()); + System.out.println("member.getDeletedAt() = " + member.isDeleted()); + + return member; + } public void validateToken(Member authMember) { if (authMember == null) { diff --git a/src/main/java/com/tikitaka/naechinso/domain/member/entity/Member.java b/src/main/java/com/tikitaka/naechinso/domain/member/entity/Member.java index 8fa7d61..cb18470 100644 --- a/src/main/java/com/tikitaka/naechinso/domain/member/entity/Member.java +++ b/src/main/java/com/tikitaka/naechinso/domain/member/entity/Member.java @@ -18,6 +18,8 @@ import com.tikitaka.naechinso.global.error.exception.BadRequestException; import com.tikitaka.naechinso.global.error.exception.UnauthorizedException; import lombok.*; +import org.hibernate.annotations.SQLDelete; +import org.hibernate.annotations.Where; import javax.persistence.*; import java.util.ArrayList; @@ -34,8 +36,9 @@ @AllArgsConstructor @NoArgsConstructor @ToString +//@SQLDelete(sql = "UPDATE member SET deleted = true WHERE mem_id = ?") +@Where(clause = "deleted = false") public class Member extends BaseEntity { - @Id @Column(name = "mem_id") @GeneratedValue @@ -127,6 +130,8 @@ public class Member extends BaseEntity { @Builder.Default private String fcmToken = ""; + private boolean deleted = Boolean.FALSE; + //멤버 디테일 정보 @OneToOne(mappedBy = "member") @JoinColumn(name = "mem_detail") diff --git a/src/main/java/com/tikitaka/naechinso/domain/member/entity/MemberDetail.java b/src/main/java/com/tikitaka/naechinso/domain/member/entity/MemberDetail.java index f52e710..27ef41a 100644 --- a/src/main/java/com/tikitaka/naechinso/domain/member/entity/MemberDetail.java +++ b/src/main/java/com/tikitaka/naechinso/domain/member/entity/MemberDetail.java @@ -6,6 +6,8 @@ import com.tikitaka.naechinso.global.config.entity.BaseEntity; import lombok.*; import org.apache.commons.lang3.StringUtils; +import org.hibernate.annotations.SQLDelete; +import org.hibernate.annotations.Where; import javax.persistence.*; import java.util.ArrayList; @@ -23,18 +25,12 @@ @AllArgsConstructor @NoArgsConstructor @ToString(exclude = {"member"}) -@EqualsAndHashCode(exclude = {"member"}) //one to one cycle hashcode 방지 public class MemberDetail extends BaseEntity { // member_detail_id => mem_id @Id @Column(name = "mem_id") private Long id; -// //추천해준 사람의 PK -// @ManyToOne -// @JoinColumn(name = "mem_id2") -// private Member recommender; - @Column(name = "mem_height") private int height; diff --git a/src/main/java/com/tikitaka/naechinso/domain/point/entity/Point.java b/src/main/java/com/tikitaka/naechinso/domain/point/entity/Point.java index 474d5b0..4493570 100644 --- a/src/main/java/com/tikitaka/naechinso/domain/point/entity/Point.java +++ b/src/main/java/com/tikitaka/naechinso/domain/point/entity/Point.java @@ -1,10 +1,8 @@ package com.tikitaka.naechinso.domain.point.entity; import com.tikitaka.naechinso.domain.member.entity.Member; -import com.tikitaka.naechinso.domain.member.entity.MemberDetail; import com.tikitaka.naechinso.domain.point.constant.PointType; import com.tikitaka.naechinso.global.config.entity.BaseEntity; -import com.tikitaka.naechinso.global.config.entity.BaseTimeEntity; import lombok.*; import javax.persistence.*; diff --git a/src/main/java/com/tikitaka/naechinso/global/config/entity/BaseEntity.java b/src/main/java/com/tikitaka/naechinso/global/config/entity/BaseEntity.java index 072c2f1..e8cfc1c 100644 --- a/src/main/java/com/tikitaka/naechinso/global/config/entity/BaseEntity.java +++ b/src/main/java/com/tikitaka/naechinso/global/config/entity/BaseEntity.java @@ -1,23 +1,28 @@ package com.tikitaka.naechinso.global.config.entity; -import com.tikitaka.naechinso.global.constant.DeleteStatus; import lombok.Getter; +import org.hibernate.annotations.SQLDelete; +import org.hibernate.annotations.Where; +import org.springframework.data.annotation.CreatedDate; +import org.springframework.data.annotation.LastModifiedDate; import org.springframework.data.jpa.domain.support.AuditingEntityListener; -import javax.persistence.*; +import javax.persistence.Column; +import javax.persistence.EntityListeners; +import javax.persistence.MappedSuperclass; +import java.time.LocalDateTime; -/** 상속받으면 createdAt, updatedAt, delStatus 자동으로 만들어주는 엔티티입니다 +/** 상속받으면 createdAt, updatedAt + * 필드 자동으로 만들어주는 엔티티입니다 * jpa의 audit(감시) 기능을 사용합니다 */ @MappedSuperclass @EntityListeners({ AuditingEntityListener.class }) @Getter -public class BaseEntity extends BaseTimeEntity { - @Enumerated(EnumType.STRING) - @Column(columnDefinition = "Text default 'N'") - private DeleteStatus delStatus=DeleteStatus.N; +public class BaseEntity { + @CreatedDate + @Column(updatable = false) + private LocalDateTime createdAt; - public void changeDeleteStatus(){ - if(this.delStatus ==DeleteStatus.Y){this.delStatus =DeleteStatus.N;} - else{this.delStatus=DeleteStatus.Y;} - } + @LastModifiedDate + private LocalDateTime updatedAt; } diff --git a/src/main/java/com/tikitaka/naechinso/global/config/entity/BaseTimeEntity.java b/src/main/java/com/tikitaka/naechinso/global/config/entity/BaseTimeEntity.java deleted file mode 100644 index fcea938..0000000 --- a/src/main/java/com/tikitaka/naechinso/global/config/entity/BaseTimeEntity.java +++ /dev/null @@ -1,26 +0,0 @@ -package com.tikitaka.naechinso.global.config.entity; - -import lombok.Getter; -import org.springframework.data.annotation.CreatedDate; -import org.springframework.data.annotation.LastModifiedDate; -import org.springframework.data.jpa.domain.support.AuditingEntityListener; - -import javax.persistence.Column; -import javax.persistence.EntityListeners; -import javax.persistence.MappedSuperclass; -import java.time.LocalDateTime; - -/** 상속받으면 createdAt, updatedAt - * 필드 자동으로 만들어주는 엔티티입니다 - * jpa의 audit(감시) 기능을 사용합니다 */ -@MappedSuperclass -@EntityListeners({ AuditingEntityListener.class }) -@Getter -public class BaseTimeEntity { - @CreatedDate - @Column(updatable = false) - private LocalDateTime createdAt; - - @LastModifiedDate - private LocalDateTime updatedAt; -} From d46159eadb6a2dbb911cc55e5ba8f7bf3b4a898e Mon Sep 17 00:00:00 2001 From: gengminy Date: Sun, 30 Oct 2022 22:38:07 +0900 Subject: [PATCH 49/72] =?UTF-8?q?:rocket:=20feat(jwt):=20=EC=9E=90?= =?UTF-8?q?=EB=8F=99=20=EB=A1=9C=EA=B7=B8=EC=9D=B8=EC=9D=84=20=EC=9C=84?= =?UTF-8?q?=ED=95=9C=20=EB=A6=AC=ED=94=84=EB=A0=88=EC=8B=9C=20=ED=86=A0?= =?UTF-8?q?=ED=81=B0=20=EC=9E=AC=EB=B0=9C=EA=B8=89=20=EA=B5=AC=ED=98=84=20?= =?UTF-8?q?#6?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../domain/member/MemberController.java | 11 ++++++++ .../domain/member/MemberService.java | 27 ++++++++++++++----- .../domain/member/entity/Member.java | 8 +++++- .../domain/member/entity/MemberDetail.java | 8 ++++-- .../config/security/jwt/JwtTokenProvider.java | 13 +++++---- .../naechinso/global/error/ErrorCode.java | 23 ++++++++-------- 6 files changed, 63 insertions(+), 27 deletions(-) diff --git a/src/main/java/com/tikitaka/naechinso/domain/member/MemberController.java b/src/main/java/com/tikitaka/naechinso/domain/member/MemberController.java index 8a55962..ad8e5ee 100644 --- a/src/main/java/com/tikitaka/naechinso/domain/member/MemberController.java +++ b/src/main/java/com/tikitaka/naechinso/domain/member/MemberController.java @@ -5,6 +5,8 @@ import com.tikitaka.naechinso.domain.pending.dto.PendingFindResponseDTO; import com.tikitaka.naechinso.domain.recommend.RecommendService; import com.tikitaka.naechinso.global.annotation.AuthMember; +import com.tikitaka.naechinso.global.common.request.TokenRequestDTO; +import com.tikitaka.naechinso.global.common.response.TokenResponseDTO; import com.tikitaka.naechinso.global.config.CommonApiResponse; import com.tikitaka.naechinso.global.config.security.jwt.JwtTokenProvider; import io.swagger.annotations.ApiOperation; @@ -80,6 +82,15 @@ public CommonApiResponse forceLogin( return CommonApiResponse.of(memberService.forceLogin(member, requestDTO)); } + @PostMapping("/reissue") + @ApiOperation(value = "리프레시 토큰을 통해 새로운 토큰을 발급받는다 (RefreshToken)") + public CommonApiResponse reissue( + @RequestHeader("Authorization") String accessToken, + @RequestHeader("Refresh") String refreshToken + ) { + return CommonApiResponse.of(memberService.reissue(accessToken, refreshToken)); + } + @PostMapping("/logout") @ApiOperation(value = "FCM Token 을 삭제하여 로그아웃 처리한다 (AccessToken)") public CommonApiResponse logout( diff --git a/src/main/java/com/tikitaka/naechinso/domain/member/MemberService.java b/src/main/java/com/tikitaka/naechinso/domain/member/MemberService.java index d3a22d7..b61e082 100644 --- a/src/main/java/com/tikitaka/naechinso/domain/member/MemberService.java +++ b/src/main/java/com/tikitaka/naechinso/domain/member/MemberService.java @@ -11,6 +11,7 @@ import com.tikitaka.naechinso.domain.pending.dto.PendingFindResponseDTO; import com.tikitaka.naechinso.domain.pending.dto.PendingUpdateMemberImageRequestDTO; import com.tikitaka.naechinso.domain.recommend.entity.Recommend; +import com.tikitaka.naechinso.global.common.request.TokenRequestDTO; import com.tikitaka.naechinso.global.common.response.TokenResponseDTO; import com.tikitaka.naechinso.global.config.security.dto.JwtDTO; import com.tikitaka.naechinso.global.config.security.jwt.JwtTokenProvider; @@ -82,6 +83,22 @@ public MemberLoginResponseDTO logout(Member authMember) { return new MemberLoginResponseDTO(""); } + /** + * 로그인 -> Fcm Token DB에 등록한다 + * */ + public TokenResponseDTO reissue(String accessToken, String refreshToken) { + String phone; + try { + phone = jwtTokenProvider.parseClaims(accessToken).getSubject(); + } catch (Exception e) { + throw new BadRequestException(ErrorCode.INVALID_REFRESH_TOKEN); + } + + jwtTokenProvider.validateRefreshToken(phone, refreshToken); + Member authMember = findByPhone(phone); + return jwtTokenProvider.generateToken(new JwtDTO(phone, authMember.getRole().toString())); + } + public MemberCommonJoinResponseDTO joinCommonMember(String phone, MemberCommonJoinRequestDTO dto) { //이미 존재하는 유저일 경우 400 @@ -189,16 +206,14 @@ public MemberDetailResponseDTO updateImage(Member authMember, MemberUpdateImageR } /** - * MemberDetail 의 프로필 이미지를 업로드 한다 + * soft delete (수정 필요) * */ public Member delete(Member authMember){ Member member = findByMember(authMember); - memberRepository.delete(authMember); - - System.out.println("member.getCreatedAt() = " + member.getCreatedAt()); - System.out.println("member.getUpdatedAt() = " + member.getUpdatedAt()); - System.out.println("member.getDeletedAt() = " + member.isDeleted()); + member.setDeleted(); + member.getDetail().setDeleted(); + memberRepository.save(member); return member; } diff --git a/src/main/java/com/tikitaka/naechinso/domain/member/entity/Member.java b/src/main/java/com/tikitaka/naechinso/domain/member/entity/Member.java index cb18470..4bfa017 100644 --- a/src/main/java/com/tikitaka/naechinso/domain/member/entity/Member.java +++ b/src/main/java/com/tikitaka/naechinso/domain/member/entity/Member.java @@ -132,6 +132,13 @@ public class Member extends BaseEntity { private boolean deleted = Boolean.FALSE; + /** + * soft delete 처리 로직 + */ + public void setDeleted(){ + this.deleted = true; + } + //멤버 디테일 정보 @OneToOne(mappedBy = "member") @JoinColumn(name = "mem_detail") @@ -191,7 +198,6 @@ public class Member extends BaseEntity { @Builder.Default private List cards = new ArrayList<>(); - public void setDetail(MemberDetail memberDetail) { this.detail = memberDetail; } diff --git a/src/main/java/com/tikitaka/naechinso/domain/member/entity/MemberDetail.java b/src/main/java/com/tikitaka/naechinso/domain/member/entity/MemberDetail.java index 27ef41a..6021afe 100644 --- a/src/main/java/com/tikitaka/naechinso/domain/member/entity/MemberDetail.java +++ b/src/main/java/com/tikitaka/naechinso/domain/member/entity/MemberDetail.java @@ -69,7 +69,12 @@ public class MemberDetail extends BaseEntity { private String images; @Column(name = "mem_image_accepted") - private Boolean image_accepted; + private boolean image_accepted; + + private boolean deleted; + public void setDeleted() { + this.deleted = true; + } // MemberDetail 을 소유한 Member 와 연결 // Member Entity 와 1:1 조인 @@ -80,7 +85,6 @@ public class MemberDetail extends BaseEntity { @JsonIgnore private Member member; - public static MemberDetail of(MemberDetailJoinRequestDTO dto) { return MemberDetail.builder() .height(dto.getHeight()) diff --git a/src/main/java/com/tikitaka/naechinso/global/config/security/jwt/JwtTokenProvider.java b/src/main/java/com/tikitaka/naechinso/global/config/security/jwt/JwtTokenProvider.java index 37ab2ad..1c35b93 100644 --- a/src/main/java/com/tikitaka/naechinso/global/config/security/jwt/JwtTokenProvider.java +++ b/src/main/java/com/tikitaka/naechinso/global/config/security/jwt/JwtTokenProvider.java @@ -71,7 +71,7 @@ public String generateRefreshToken(JwtDTO jwtDTO) { .signWith(SignatureAlgorithm.HS512, encodedKey) .compact(); - //redis에 해당 userId 의 리프레시 토큰 등록 + //redis에 해당 phone number 의 리프레시 토큰 등록 redisService.setValues( jwtDTO.getPhoneNumber(), refreshToken, @@ -192,13 +192,13 @@ public boolean validateToken(HttpServletRequest request, String token) { /** Redis Memory 의 RefreshToken 과 * User 의 RefreshToken 이 일치하는지 확인 - * @param userId 검증하려는 유저 아이디 + * @param phone 검증하려는 유저 휴대전화 * @param refreshToken 검증하려는 리프레시 토큰 */ - public void validateRefreshToken(String userId, String refreshToken) { - String redisRt = redisService.getValues(userId); - if (!refreshToken.equals(redisRt)) { - throw new BadRequestException(ErrorCode.EXPIRED_TOKEN); + public void validateRefreshToken(String phone, String refreshToken) { + String redisRefreshToken = redisService.getValues(phone); + if (!refreshToken.equals(redisRefreshToken)) { + throw new BadRequestException(ErrorCode.EXPIRED_REFRESH_TOKEN); } } @@ -215,7 +215,6 @@ public String parsePhoneByRegisterToken(HttpServletRequest request) { return parseClaims(registerToken).getSubject(); } - /** * JWT 토큰에서 claims 추출 * @param accessToken 추출하고 싶은 AccessToken (JWT) diff --git a/src/main/java/com/tikitaka/naechinso/global/error/ErrorCode.java b/src/main/java/com/tikitaka/naechinso/global/error/ErrorCode.java index 053db26..0565332 100644 --- a/src/main/java/com/tikitaka/naechinso/global/error/ErrorCode.java +++ b/src/main/java/com/tikitaka/naechinso/global/error/ErrorCode.java @@ -36,17 +36,18 @@ public enum ErrorCode { EXPIRED_TOKEN(UNAUTHORIZED, "AUTH001", "만료된 엑세스 토큰입니다"), INVALID_REFRESH_TOKEN(UNAUTHORIZED, "AUTH002", "리프레시 토큰이 유효하지 않습니다"), MISMATCH_REFRESH_TOKEN(UNAUTHORIZED, "AUTH003", "리프레시 토큰의 유저 정보가 일치하지 않습니다"), - INVALID_AUTH_TOKEN(UNAUTHORIZED, "AUTH004", "권한 정보가 없는 토큰입니다"), - UNAUTHORIZED_USER(UNAUTHORIZED, "AUTH005", "로그인이 필요합니다"), - REFRESH_TOKEN_NOT_FOUND(UNAUTHORIZED, "AUTH006", "로그아웃 된 사용자입니다"), - FORBIDDEN_USER(FORBIDDEN, "AUTH007", "권한이 없는 유저입니다"), - UNSUPPORTED_TOKEN(UNAUTHORIZED, "AUTH008", "지원하지 않는 토큰입니다"), - INVALID_SIGNATURE(UNAUTHORIZED, "AUTH009", "잘못된 JWT 서명입니다"), - MISMATCH_VERIFICATION_CODE(UNAUTHORIZED, "AUTH010", "인증번호가 일치하지 않습니다"), - EXPIRED_VERIFICATION_CODE(UNAUTHORIZED, "AUTH011", "인증번호가 만료되었습니다"), - INVALID_USER_TOKEN(UNAUTHORIZED, "AUTH012", "서버에 토큰과 일치하는 정보가 없습니다"), - - LOGIN_FAILED(UNAUTHORIZED, "AUTH013", "로그인에 실패했습니다"), + EXPIRED_REFRESH_TOKEN(UNAUTHORIZED, "AUTH004", "만료된 리프레시 토큰입니다"), + INVALID_AUTH_TOKEN(UNAUTHORIZED, "AUTH005", "권한 정보가 없는 토큰입니다"), + UNAUTHORIZED_USER(UNAUTHORIZED, "AUTH006", "로그인이 필요합니다"), + REFRESH_TOKEN_NOT_FOUND(UNAUTHORIZED, "AUTH007", "로그아웃 된 사용자입니다"), + FORBIDDEN_USER(FORBIDDEN, "AUTH008", "권한이 없는 유저입니다"), + UNSUPPORTED_TOKEN(UNAUTHORIZED, "AUTH009", "지원하지 않는 토큰입니다"), + INVALID_SIGNATURE(UNAUTHORIZED, "AUTH010", "잘못된 JWT 서명입니다"), + MISMATCH_VERIFICATION_CODE(UNAUTHORIZED, "AUTH011", "인증번호가 일치하지 않습니다"), + EXPIRED_VERIFICATION_CODE(UNAUTHORIZED, "AUTH012", "인증번호가 만료되었습니다"), + INVALID_USER_TOKEN(UNAUTHORIZED, "AUTH013", "서버에 토큰과 일치하는 정보가 없습니다"), + + LOGIN_FAILED(UNAUTHORIZED, "AUTH014", "로그인에 실패했습니다"), /* User 관련 오류 */ From 0ea8f3ea52eaa1bdf60b8a9e363d05afa5b4e861 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EB=85=B8=EA=B2=BD=EB=AF=BC?= <72291860+gengminy@users.noreply.github.com> Date: Sun, 30 Oct 2022 22:53:25 +0900 Subject: [PATCH 50/72] Update deploy-dev.yml --- .github/workflows/deploy-dev.yml | 3 +++ 1 file changed, 3 insertions(+) diff --git a/.github/workflows/deploy-dev.yml b/.github/workflows/deploy-dev.yml index 3da86ce..27f2d26 100644 --- a/.github/workflows/deploy-dev.yml +++ b/.github/workflows/deploy-dev.yml @@ -25,8 +25,11 @@ jobs: run: | touch ./src/main/resources/application-dev.yml echo "$ENV_PROPERTIES_DEV" > ./src/main/resources/application-dev.yml + touch ./src/main/resources/naechinso-fcm.json + echo "$FCM_JSON" > ./src/main/resources/naechinso-fcm.json env: ENV_PROPERTIES_DEV: ${{ secrets.ENV_PROPERTIES_DEV }} + FCM_JSON: ${{ secrets.FCM_JSON }} #Grant gradlew Permission - name: Grant execute permission for gradlew From 48727fa5ceb3a06efbba56b2971bf9f6d026f7dd Mon Sep 17 00:00:00 2001 From: gengminy Date: Tue, 1 Nov 2022 12:52:34 +0900 Subject: [PATCH 51/72] =?UTF-8?q?:hammer:=20fix(s3):=20multipart=20?= =?UTF-8?q?=EC=B5=9C=EB=8C=80=20=EC=9A=A9=EB=9F=89=20=EC=84=A4=EC=A0=95=20?= =?UTF-8?q?#35?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../domain/member/MemberService.java | 14 ++++++-- .../config/security/jwt/JwtTokenProvider.java | 36 +++++++++++++++++++ .../naechinso/global/error/ErrorCode.java | 2 ++ .../global/error/GlobalExceptionHandler.java | 12 +++++++ src/main/resources/application.yml | 5 +++ 5 files changed, 67 insertions(+), 2 deletions(-) diff --git a/src/main/java/com/tikitaka/naechinso/domain/member/MemberService.java b/src/main/java/com/tikitaka/naechinso/domain/member/MemberService.java index b61e082..25827a5 100644 --- a/src/main/java/com/tikitaka/naechinso/domain/member/MemberService.java +++ b/src/main/java/com/tikitaka/naechinso/domain/member/MemberService.java @@ -67,7 +67,7 @@ public MemberLoginResponseDTO forceLogin(Member authMember, MemberLoginRequestDT } /** - * 로그아웃 -> Fcm Token DB에서 삭제한다 + * 로그아웃 -> Register Token 및 Fcm Token DB에서 삭제한다 * */ public MemberLoginResponseDTO logout(Member authMember) { Member member = findByMember(authMember); @@ -77,6 +77,10 @@ public MemberLoginResponseDTO logout(Member authMember) { throw new BadRequestException(ErrorCode.USER_ALREADY_LOGGED_OUT); } + //redis 에서 registerToken 삭제 + jwtTokenProvider.deleteRegisterToken(member.getPhone()); + + //푸시 알림 등록 해제 member.setFcmToken(""); memberRepository.save(member); @@ -85,17 +89,23 @@ public MemberLoginResponseDTO logout(Member authMember) { /** * 로그인 -> Fcm Token DB에 등록한다 + * @// TODO: 2022/10/30 노션에 정리 * */ public TokenResponseDTO reissue(String accessToken, String refreshToken) { String phone; + + if (!jwtTokenProvider.validateTokenExceptExpiration(accessToken)){ + throw new BadRequestException(ErrorCode.INVALID_ACCESS_TOKEN); + } + try { phone = jwtTokenProvider.parseClaims(accessToken).getSubject(); } catch (Exception e) { throw new BadRequestException(ErrorCode.INVALID_REFRESH_TOKEN); } - jwtTokenProvider.validateRefreshToken(phone, refreshToken); Member authMember = findByPhone(phone); + jwtTokenProvider.validateRefreshToken(phone, refreshToken); return jwtTokenProvider.generateToken(new JwtDTO(phone, authMember.getRole().toString())); } diff --git a/src/main/java/com/tikitaka/naechinso/global/config/security/jwt/JwtTokenProvider.java b/src/main/java/com/tikitaka/naechinso/global/config/security/jwt/JwtTokenProvider.java index 1c35b93..d2ad737 100644 --- a/src/main/java/com/tikitaka/naechinso/global/config/security/jwt/JwtTokenProvider.java +++ b/src/main/java/com/tikitaka/naechinso/global/config/security/jwt/JwtTokenProvider.java @@ -20,6 +20,8 @@ import javax.servlet.http.HttpServletRequest; import java.time.Duration; +import java.time.LocalDate; +import java.time.LocalDateTime; import java.util.*; @Slf4j @@ -118,6 +120,22 @@ public String generateRegisterToken(JwtDTO jwtDTO) return registerToken; } + /** Redis 에서 RegistrerToken 을 제거 + * @param phone 로그아웃 요청 유저 + * @return true if redis 서버에 토큰이 있었을 경우 + * false if 토큰이 없었을 경우 + */ + public boolean deleteRegisterToken(String phone) { + try { + if (redisService.hasKey(phone)) { + redisService.deleteValues(phone); + return true; + } + } catch (Exception e) { + log.error("Redis 로그아웃 요청을 실패했습니다"); + } + return false; + } public Authentication getAuthentication(HttpServletRequest request, String accessToken) { Claims claims = parseClaims(accessToken); @@ -189,6 +207,24 @@ public boolean validateToken(HttpServletRequest request, String token) { } return false; } + /** + * 토큰 예외 중 만료 상황만 검증 함수 + * @param token 검사하려는 JWT 토큰 + * @returns boolean + * */ + public boolean validateTokenExceptExpiration(String token) { + final String encodedKey = Base64.getEncoder().encodeToString(JWT_SECRET.getBytes()); + try { + Jwts.parser().setSigningKey(encodedKey).parseClaimsJws(token); + return true; +// Jws claims = Jwts.parser().setSigningKey(encodedKey).parseClaimsJws(token); +// return claims.getBody().getExpiration().before(new Date()); + } catch(ExpiredJwtException e) { + return true; + } catch (Exception e) { + return false; + } + } /** Redis Memory 의 RefreshToken 과 * User 의 RefreshToken 이 일치하는지 확인 diff --git a/src/main/java/com/tikitaka/naechinso/global/error/ErrorCode.java b/src/main/java/com/tikitaka/naechinso/global/error/ErrorCode.java index 0565332..2c7a7f1 100644 --- a/src/main/java/com/tikitaka/naechinso/global/error/ErrorCode.java +++ b/src/main/java/com/tikitaka/naechinso/global/error/ErrorCode.java @@ -22,6 +22,7 @@ public enum ErrorCode { CANNOT_CREATE_RECOMMEND_REQUEST(INTERNAL_SERVER_ERROR, "C007", "추천사 요청에 실패했습니다"), NOT_MULTIPART_HEADER(BAD_REQUEST, "C008", "Multipart 헤더가 아닙니다"), AMAZON_ACCESS_DENIED(FORBIDDEN, "C009", "Amazon S3 접근이 거부되었습니다"), + MAX_FILE_SIZE_EXCEEDED(BAD_REQUEST, "C010", "허용된 최대 파일 크기를 초과했습니다"), /* DB 관련 오류 */ @@ -48,6 +49,7 @@ public enum ErrorCode { INVALID_USER_TOKEN(UNAUTHORIZED, "AUTH013", "서버에 토큰과 일치하는 정보가 없습니다"), LOGIN_FAILED(UNAUTHORIZED, "AUTH014", "로그인에 실패했습니다"), + INVALID_ACCESS_TOKEN(UNAUTHORIZED, "AUTH015", "유효하지 않은 엑세스 토큰입니다"), /* User 관련 오류 */ diff --git a/src/main/java/com/tikitaka/naechinso/global/error/GlobalExceptionHandler.java b/src/main/java/com/tikitaka/naechinso/global/error/GlobalExceptionHandler.java index 96802cf..dcadb94 100644 --- a/src/main/java/com/tikitaka/naechinso/global/error/GlobalExceptionHandler.java +++ b/src/main/java/com/tikitaka/naechinso/global/error/GlobalExceptionHandler.java @@ -15,6 +15,7 @@ import org.springframework.web.bind.annotation.ExceptionHandler; import org.springframework.web.bind.annotation.RestControllerAdvice; import org.springframework.web.method.annotation.MethodArgumentTypeMismatchException; +import org.springframework.web.multipart.MaxUploadSizeExceededException; import org.springframework.web.multipart.MultipartException; import java.util.Arrays; @@ -108,6 +109,17 @@ protected ResponseEntity handleBadCredentialsException(BadCredent return new ResponseEntity<>(response, HttpStatus.UNAUTHORIZED); } + /** + * 업로드 최대 용량을 초과했을 경우 + */ + @ExceptionHandler({MaxUploadSizeExceededException.class}) + protected ResponseEntity handleMultipartException(MaxUploadSizeExceededException e) { + log.error("handleMaxUploadSizeExceededException", e); + final ErrorResponse response = ErrorResponse.of(ErrorCode.MAX_FILE_SIZE_EXCEEDED); + return new ResponseEntity<>(response, HttpStatus.BAD_REQUEST); + } + + /** * 파일 업로드 시 멀티파트 헤더를 설정하지 않았을때 에러 */ diff --git a/src/main/resources/application.yml b/src/main/resources/application.yml index 7892517..789e850 100644 --- a/src/main/resources/application.yml +++ b/src/main/resources/application.yml @@ -2,6 +2,11 @@ server: port: 8080 spring: + servlet: + #file upload size + multipart: + max-file-size: 3MB + profiles: active: local # Using POSTGRESQL From e1abbc7d3365e2b8143d484adafb37da3cb55382 Mon Sep 17 00:00:00 2001 From: gengminy Date: Tue, 1 Nov 2022 13:05:36 +0900 Subject: [PATCH 52/72] =?UTF-8?q?:hammer:=20fix(s3):=20nginx=20max=20body?= =?UTF-8?q?=20=EC=88=98=EC=A0=95=20#57?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .platform/nginx/nginx.conf | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.platform/nginx/nginx.conf b/.platform/nginx/nginx.conf index e604b45..5e4d910 100644 --- a/.platform/nginx/nginx.conf +++ b/.platform/nginx/nginx.conf @@ -14,6 +14,8 @@ http { include /etc/nginx/mime.types; default_type application/octet-stream; + client_max_body_size 4M; + log_format main '$remote_addr - $remote_user [$time_local] "$request" ' '$status $body_bytes_sent "$http_referer" ' '"$http_user_agent" "$http_x_forwarded_for"'; From 3309a2211282c9940916796adaa85b8a57bb572f Mon Sep 17 00:00:00 2001 From: gengminy Date: Tue, 1 Nov 2022 13:06:42 +0900 Subject: [PATCH 53/72] =?UTF-8?q?:hammer:=20fix(s3):=20tomcat=20max=20file?= =?UTF-8?q?=20size=20=EC=84=A4=EC=A0=95=20#57?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/main/resources/application.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/resources/application.yml b/src/main/resources/application.yml index 789e850..612008e 100644 --- a/src/main/resources/application.yml +++ b/src/main/resources/application.yml @@ -3,8 +3,8 @@ server: spring: servlet: - #file upload size multipart: + #file upload size max-file-size: 3MB profiles: From ea880a35abee9073d2f3c791728a1e4f32f735f6 Mon Sep 17 00:00:00 2001 From: gengminy Date: Tue, 1 Nov 2022 14:20:04 +0900 Subject: [PATCH 54/72] =?UTF-8?q?:hammer:=20fix(erorr):=20RequestPartExcep?= =?UTF-8?q?tion=20=EC=B6=94=EA=B0=80=20#57?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../com/tikitaka/naechinso/global/error/ErrorCode.java | 1 + .../naechinso/global/error/GlobalExceptionHandler.java | 10 ++++++++++ 2 files changed, 11 insertions(+) diff --git a/src/main/java/com/tikitaka/naechinso/global/error/ErrorCode.java b/src/main/java/com/tikitaka/naechinso/global/error/ErrorCode.java index 2c7a7f1..8d49274 100644 --- a/src/main/java/com/tikitaka/naechinso/global/error/ErrorCode.java +++ b/src/main/java/com/tikitaka/naechinso/global/error/ErrorCode.java @@ -23,6 +23,7 @@ public enum ErrorCode { NOT_MULTIPART_HEADER(BAD_REQUEST, "C008", "Multipart 헤더가 아닙니다"), AMAZON_ACCESS_DENIED(FORBIDDEN, "C009", "Amazon S3 접근이 거부되었습니다"), MAX_FILE_SIZE_EXCEEDED(BAD_REQUEST, "C010", "허용된 최대 파일 크기를 초과했습니다"), + INVALID_REQUEST_PART(BAD_REQUEST, "C011", "올바르지 않은 파라미터 형식입니다"), /* DB 관련 오류 */ diff --git a/src/main/java/com/tikitaka/naechinso/global/error/GlobalExceptionHandler.java b/src/main/java/com/tikitaka/naechinso/global/error/GlobalExceptionHandler.java index dcadb94..83f593e 100644 --- a/src/main/java/com/tikitaka/naechinso/global/error/GlobalExceptionHandler.java +++ b/src/main/java/com/tikitaka/naechinso/global/error/GlobalExceptionHandler.java @@ -17,6 +17,7 @@ import org.springframework.web.method.annotation.MethodArgumentTypeMismatchException; import org.springframework.web.multipart.MaxUploadSizeExceededException; import org.springframework.web.multipart.MultipartException; +import org.springframework.web.multipart.support.MissingServletRequestPartException; import java.util.Arrays; @@ -119,6 +120,15 @@ protected ResponseEntity handleMultipartException(MaxUploadSizeEx return new ResponseEntity<>(response, HttpStatus.BAD_REQUEST); } + /** + * RequestPart 의 인자로 잘못된 값을 넘겼을 경우 발생하는 에러 + */ + @ExceptionHandler({MissingServletRequestPartException.class}) + protected ResponseEntity handleMultipartException(MissingServletRequestPartException e) { + log.error("handleMissingServletRequestPartException", e); + final ErrorResponse response = ErrorResponse.of(ErrorCode.INVALID_REQUEST_PART); + return new ResponseEntity<>(response, HttpStatus.BAD_REQUEST); + } /** * 파일 업로드 시 멀티파트 헤더를 설정하지 않았을때 에러 From 213871dce4ce3b44fd1693bfcbfaeb3dddb38058 Mon Sep 17 00:00:00 2001 From: gengminy Date: Thu, 3 Nov 2022 15:10:42 +0900 Subject: [PATCH 55/72] =?UTF-8?q?:hammer:=20fix(test):=20=ED=85=8C?= =?UTF-8?q?=EC=8A=A4=ED=8A=B8=EC=9A=A9=20=EC=BB=A8=ED=8A=B8=EB=A1=A4?= =?UTF-8?q?=EB=9F=AC=20pending=20=EC=B4=88=EA=B8=B0=ED=99=94=20=EC=B6=94?= =?UTF-8?q?=EA=B0=80=20#27?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../com/tikitaka/naechinso/domain/TestController.java | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/src/main/java/com/tikitaka/naechinso/domain/TestController.java b/src/main/java/com/tikitaka/naechinso/domain/TestController.java index 70c394a..f6d9ec5 100644 --- a/src/main/java/com/tikitaka/naechinso/domain/TestController.java +++ b/src/main/java/com/tikitaka/naechinso/domain/TestController.java @@ -14,7 +14,9 @@ import com.tikitaka.naechinso.domain.member.dto.*; import com.tikitaka.naechinso.domain.member.entity.Member; import com.tikitaka.naechinso.domain.member.entity.MemberDetail; +import com.tikitaka.naechinso.domain.pending.PendingRepository; import com.tikitaka.naechinso.domain.pending.PendingService; +import com.tikitaka.naechinso.domain.point.PointRepository; import com.tikitaka.naechinso.domain.recommend.RecommendRepository; import com.tikitaka.naechinso.domain.recommend.RecommendService; import com.tikitaka.naechinso.domain.recommend.dto.RecommendBySenderRequestDTO; @@ -47,10 +49,14 @@ public class TestController { private final RecommendService recommendService; private final RecommendRepository recommendRepository; private final PendingService pendingService; + private final PendingRepository pendingRepository; + private final CardService cardService; private final CardRepository cardRepository; private final MatchService matchService; private final MatchRepository matchRepository; + private final PointRepository pointRepository; + @GetMapping("/create-recommend-request-member") @ApiOperation(value = "[*TEST*] 추천사를 요청하는 유저를 생성하고 엑세스 토큰을 반환한다") @@ -480,6 +486,8 @@ public CommonApiResponse createMatch( @ApiOperation(value = "[*TEST*] 모든 DB 테이블을 초기화") public CommonApiResponse dropAllTable(){ matchRepository.deleteAll(); + pointRepository.deleteAll(); + pendingRepository.deleteAll(); recommendRepository.deleteAll(); cardRepository.deleteAll(); memberDetailRepository.deleteAll(); From 96d0816cded6df509cd5d1c7f85d93ebeb7b1b7a Mon Sep 17 00:00:00 2001 From: gengminy Date: Thu, 3 Nov 2022 18:14:32 +0900 Subject: [PATCH 56/72] =?UTF-8?q?:hammer:=20fix(member):=20appeals,=20pers?= =?UTF-8?q?onalities=20=ED=95=84=EB=93=9C=20=EB=B3=80=EA=B2=BD=20#39?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../naechinso/domain/TestController.java | 66 +++++++++---------- .../CardOppositeMemberProfileResponseDTO.java | 8 +-- .../card/dto/CardThumbnailResponseDTO.java | 4 +- .../dto/MatchBasicProfileResponseDTO.java | 8 +-- .../dto/MatchOpenProfileResponseDTO.java | 8 +-- .../match/dto/MatchThumbnailResponseDTO.java | 4 +- .../dto/MemberDetailJoinRequestDTO.java | 11 +++- .../member/dto/MemberDetailResponseDTO.java | 5 +- .../dto/MemberDetailUpdateRequestDTO.java | 7 +- .../dto/MemberOppositeProfileResponseDTO.java | 8 +-- .../domain/member/entity/MemberDetail.java | 15 +++-- .../domain/recommend/RecommendService.java | 4 +- .../dto/RecommendAcceptRequestDTO.java | 12 ++-- .../dto/RecommendBySenderRequestDTO.java | 12 ++-- ...ommendMemberAcceptAndUpdateRequestDTO.java | 12 ++-- .../dto/RecommendMemberAcceptRequestDTO.java | 12 ++-- .../recommend/dto/RecommendResponseDTO.java | 6 +- .../domain/recommend/entity/Recommend.java | 19 ++++-- 18 files changed, 115 insertions(+), 106 deletions(-) diff --git a/src/main/java/com/tikitaka/naechinso/domain/TestController.java b/src/main/java/com/tikitaka/naechinso/domain/TestController.java index f6d9ec5..0227aff 100644 --- a/src/main/java/com/tikitaka/naechinso/domain/TestController.java +++ b/src/main/java/com/tikitaka/naechinso/domain/TestController.java @@ -26,6 +26,7 @@ import io.swagger.annotations.ApiOperation; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; +import org.apache.commons.lang3.StringUtils; import org.springframework.web.bind.annotation.*; import springfox.documentation.annotations.ApiIgnore; @@ -120,10 +121,9 @@ public CommonApiResponse generateRecommendReceiver( .builder() .age(25) .period("1년") - .appeal("짱") + .appeals(List.of("[패션센스 \uD83E\uDDE5", "사랑꾼 \uD83D\uDC97", "애교쟁이 \uD83D\uDE18")) .phone("01012345678") .meet("CMC에서") - .personality("최고") .gender(Gender.M) .name("닉") .build()); @@ -214,10 +214,9 @@ public CommonApiResponse createJobPendingMemberAndRecommendOther( .builder() .age(25) .period("1년") - .appeal("짱") + .appeals(List.of("[패션센스 \uD83E\uDDE5", "사랑꾼 \uD83D\uDC97", "애교쟁이 \uD83D\uDE18")) .phone("01011111111") .meet("CMC에서") - .personality("최고") .gender(Gender.M) .name("닉") .build())); @@ -288,11 +287,10 @@ public CommonApiResponse createTwoRegularMember() { .builder() .age(25) .period("3달") - .appeal("멋짐") + .appeals(List.of("[패션센스 \uD83E\uDDE5", "사랑꾼 \uD83D\uDC97", "애교쟁이 \uD83D\uDE18")) .appealDetail("짱짱짱 멋짐") .phone("01012345678") .meet("테스트중에") - .personality("착함") .gender(Gender.M) .name("박스") .build()); @@ -302,11 +300,10 @@ public CommonApiResponse createTwoRegularMember() { .builder() .age(25) .period("1년") - .appeal("짱") + .appeals(List.of("[패션센스 \uD83E\uDDE5", "사랑꾼 \uD83D\uDC97", "애교쟁이 \uD83D\uDE18")) .appealDetail("짱짱짱 멋짐") .phone("01011111111") .meet("CMC에서") - .personality("최고") .gender(Gender.M) .name("닉") .build()); @@ -323,7 +320,7 @@ public CommonApiResponse createTwoRegularMember() { .image_accepted(true) .introduce("반갑습니다") .mbti("ESTJ") - .personality("직관적") + .personalities("패션센스 \uD83E\uDDE5,사랑꾼 \uD83D\uDC97,애교쟁이 \uD83D\uDE18") .religion("무교") .smoke("비흡연자") .style("좋음") @@ -340,7 +337,7 @@ public CommonApiResponse createTwoRegularMember() { .images("imppp.jpg, ppap.png, good.jpg") .introduce("안녕하세요") .mbti("INTJ") - .personality("직관적") + .personalities("패션센스 \uD83E\uDDE5,사랑꾼 \uD83D\uDC97,애교쟁이 \uD83D\uDE18") .religion("무교") .smoke("비흡연자") .style("개굿") @@ -354,7 +351,7 @@ public CommonApiResponse createTwoRegularMember() { @GetMapping("/create-multiple-users") @ApiOperation(value = "[*TEST*] 정회원으로 가입한 유저를 남녀 10명씩 생성하고, 그 중 마지막 여성 멤버 하나의 엑세스 토큰 반환") public CommonApiResponse createMultipleMembers() { - List adminMemberInfo = Arrays.asList("01012345678", 25, Gender.M, "노경닉", "edu-image-admin.jpg", "홍익", "대학교", "컴퓨터공학과", "1~3년", "CMC에서 만남", "착함", "자기관리, 귀여워, 차분해", "자기 일을 진짜 책임감 있게 잘하고 주변을 늘 먼저 생각하는 친구야", "서울시 마포구", "1병", 180, "내친소 사용하기", "profile-001-01.png,profile-001-02.png,profile-001-03.png", "반갑습니다 내친소 여러분!", "ESTJ", "열정적인, 상냥한, 섬세한", "무교", "비흡연자", "같이 취미를 즐길 수 있는 연애를 하고 싶어"); //어드민 겸 추천인 + List adminMemberInfo = Arrays.asList("01012345678", 25, Gender.M, "노경닉", "edu-image-admin.jpg", "홍익", "대학교", "컴퓨터공학과", "1~3년", "CMC에서 만남", "착함", "패션센스 \uD83E\uDDE5,사랑꾼 \uD83D\uDC97,애교쟁이 \uD83D\uDE18", "자기 일을 진짜 책임감 있게 잘하고 주변을 늘 먼저 생각하는 친구야", "서울시 마포구", "1병", 180, "내친소 사용하기", "profile-001-01.png,profile-001-02.png,profile-001-03.png", "반갑습니다 내친소 여러분!", "ESTJ", "열정적인 \uD83D\uDD25,지적인 \uD83E\uDDD0,상냥한 ☺️", "무교", "비흡연자", "같이 취미를 즐길 수 있는 연애를 하고 싶어"); //어드민 겸 추천인 Member adminMember = memberService.findByPhone(memberService.joinCommonMember( (String) adminMemberInfo.get(0), @@ -378,27 +375,27 @@ public CommonApiResponse createMultipleMembers() { memberRepository.save(adminMember); final List> joinRequestList = Arrays.asList( - Arrays.asList("01011111111", 25, Gender.M, "허시준", "edu-image001.jpg", "서강", "대학교", "컴퓨터공학과", "1~3년", "CMC에서 만남", "착함", "자기관리, 귀여워, 차분해", "자기 일을 진짜 책임감 있게 잘하고 주변을 늘 먼저 생각하는 친구야", "서울시 마포구", "1병", 180, "내친소 사용하기", "profile-001-01.png,profile-001-02.png,profile-001-03.png", "반갑습니다 내친소 여러분!", "ESTJ", "열정적인, 상냥한, 섬세한", "무교", "비흡연자", "같이 취미를 즐길 수 있는 연애를 하고 싶어"), - Arrays.asList("01012222222", 26, Gender.M, "민성진", "edu-image002.jpg", "한국", "고등학교", "자동차정비", "1~3년", "CMC에서 만남", "착함", "자기관리, 귀여워, 차분해", "자기 일을 진짜 책임감 있게 잘하고 주변을 늘 먼저 생각하는 친구야", "서울시 마포구", "1병", 185, "내친소 사용하기", "profile-001-01.png,profile-001-02.png,profile-001-03.png", "반갑습니다 내친소 여러분!", "INFP", "열정적인, 상냥한, 섬세한", "무교", "비흡연자", "같이 취미를 즐길 수 있는 연애를 하고 싶어"), - Arrays.asList("01013333333", 27, Gender.M, "김상혁", "edu-image003.jpg", "서울", "대학원", "인공지능공학", "1~3년", "CMC에서 만남", "착함", "자기관리, 귀여워, 차분해", "자기 일을 진짜 책임감 있게 잘하고 주변을 늘 먼저 생각하는 친구야", "서울시 마포구", "1병", 182, "내친소 사용하기", "profile-001-01.png,profile-001-02.png,profile-001-03.png", "반갑습니다 내친소 여러분!", "ESTJ", "열정적인, 상냥한, 섬세한", "기독교", "비흡연자", "같이 취미를 즐길 수 있는 연애를 하고 싶어"), - Arrays.asList("01014444444", 28, Gender.M, "권영성", "edu-image004.jpg", "홍익", "대학교", "시각디자인학과", "1~3년", "CMC에서 만남", "착함", "자기관리, 귀여워, 차분해", "자기 일을 진짜 책임감 있게 잘하고 주변을 늘 먼저 생각하는 친구야", "서울시 마포구", "1병", 183, "내친소 사용하기", "profile-001-01.png,profile-001-02.png,profile-001-03.png", "반갑습니다 내친소 여러분!", "INFJ", "열정적인, 상냥한, 섬세한", "불교", "비흡연자", "같이 취미를 즐길 수 있는 연애를 하고 싶어"), - Arrays.asList("01015555555", 29, Gender.M, "배규빈", "edu-image005.jpg", "한성", "고등학교", "상업", "3~5년", "CMC에서 만남", "착함", "자기관리, 귀여워, 차분해", "자기 일을 진짜 책임감 있게 잘하고 주변을 늘 먼저 생각하는 친구야", "서울시 마포구", "1병", 178, "내친소 사용하기", "profile-001-01.png,profile-001-02.png,profile-001-03.png", "반갑습니다 내친소 여러분!", "ESTJ", "열정적인, 상냥한, 섬세한", "무교", "비흡연자", "같이 취미를 즐길 수 있는 연애를 하고 싶어"), - Arrays.asList("01016666666", 30, Gender.M, "권민기", "edu-image006.jpg", "서울", "고등학교", "디자인", "3~5년", "CMC에서 만남", "착함", "자기관리, 귀여워, 차분해", "자기 일을 진짜 책임감 있게 잘하고 주변을 늘 먼저 생각하는 친구야", "서울시 마포구", "1병", 172, "내친소 사용하기", "profile-001-01.png,profile-001-02.png,profile-001-03.png", "반갑습니다 내친소 여러분!", "ESFJ", "열정적인, 상냥한, 섬세한", "무교", "비흡연자", "같이 취미를 즐길 수 있는 연애를 하고 싶어"), - Arrays.asList("01017777777", 31, Gender.M, "김민성", "edu-image007.jpg", "연세", "대학원", "영어영문학과", "1~3년", "CMC에서 만남", "착함", "자기관리, 귀여워, 차분해", "자기 일을 진짜 책임감 있게 잘하고 주변을 늘 먼저 생각하는 친구야", "서울시 마포구", "1병", 173, "내친소 사용하기", "profile-001-01.png,profile-001-02.png,profile-001-03.png", "반갑습니다 내친소 여러분!", "ENFP", "열정적인, 상냥한, 섬세한", "기독교", "비흡연자", "같이 취미를 즐길 수 있는 연애를 하고 싶어"), - Arrays.asList("01018888888", 32, Gender.M, "임정혁", "edu-image008.jpg", "연세", "대학교", "전기전자공학과", "1~3년", "CMC에서 만남", "착함", "자기관리, 귀여워, 차분해", "자기 일을 진짜 책임감 있게 잘하고 주변을 늘 먼저 생각하는 친구야", "서울시 마포구", "1병", 175, "내친소 사용하기", "profile-001-01.png,profile-001-02.png,profile-001-03.png", "반갑습니다 내친소 여러분!", "ESTJ", "열정적인, 상냥한, 섬세한", "무교", "비흡연자", "같이 취미를 즐길 수 있는 연애를 하고 싶어"), - Arrays.asList("01019999999", 33, Gender.M, "성재오", "edu-image009.jpg", "이대부속", "고등학교", "공학", "1~3년", "CMC에서 만남", "착함", "자기관리, 귀여워, 차분해", "자기 일을 진짜 책임감 있게 잘하고 주변을 늘 먼저 생각하는 친구야", "서울시 마포구", "1병", 168, "내친소 사용하기", "profile-001-01.png,profile-001-02.png,profile-001-03.png", "반갑습니다 내친소 여러분!", "ESTJ", "열정적인, 상냥한, 섬세한", "무교", "비흡연자", "같이 취미를 즐길 수 있는 연애를 하고 싶어"), - Arrays.asList("01010000000", 25, Gender.M, "차재훈", "edu-image010.jpg", "국민", "대학교", "미디어학과", "1~3년", "CMC에서 만남", "착함", "자기관리, 귀여워, 차분해", "자기 일을 진짜 책임감 있게 잘하고 주변을 늘 먼저 생각하는 친구야", "서울시 마포구", "1병", 176, "내친소 사용하기", "profile-001-01.png,profile-001-02.png,profile-001-03.png", "반갑습니다 내친소 여러분!", "ESTP", "열정적인, 상냥한, 섬세한", "무교", "비흡연자", "같이 취미를 즐길 수 있는 연애를 하고 싶어"), - - Arrays.asList("01022200000", 25, Gender.W, "민장효", "edu-image011.jpg", "서강", "대학원", "물류학과", "1~3년", "CMC에서 만남", "착함", "자기관리, 귀여워, 차분해", "자기 일을 진짜 책임감 있게 잘하고 주변을 늘 먼저 생각하는 친구야", "서울시 마포구", "1병", 160, "내친소 사용하기", "profile-001-01.png,profile-001-02.png,profile-001-03.png", "반갑습니다 내친소 여러분!", "INFP", "열정적인, 상냥한, 섬세한", "무교", "비흡연자", "같이 취미를 즐길 수 있는 연애를 하고 싶어"), - Arrays.asList("01022211111", 25, Gender.W, "김민서", "edu-image012.jpg", "홍익", "대학교", "조소과", "1~3년", "CMC에서 만남", "착함", "자기관리, 귀여워, 차분해", "자기 일을 진짜 책임감 있게 잘하고 주변을 늘 먼저 생각하는 친구야", "서울시 마포구", "1병", 162, "내친소 사용하기", "profile-001-01.png,profile-001-02.png,profile-001-03.png", "반갑습니다 내친소 여러분!", "ESTJ", "열정적인, 상냥한, 섬세한", "무교", "비흡연자", "같이 취미를 즐길 수 있는 연애를 하고 싶어"), - Arrays.asList("01022222222", 25, Gender.W, "노혜지", "edu-image013.jpg", "한국", "고등학교", "디자인", "1~3년", "CMC에서 만남", "착함", "자기관리, 귀여워, 차분해", "자기 일을 진짜 책임감 있게 잘하고 주변을 늘 먼저 생각하는 친구야", "서울시 마포구", "1병", 165, "내친소 사용하기", "profile-001-01.png,profile-001-02.png,profile-001-03.png", "반갑습니다 내친소 여러분!", "ENFP", "열정적인, 상냥한, 섬세한", "기독교", "비흡연자", "같이 취미를 즐길 수 있는 연애를 하고 싶어"), - Arrays.asList("01022233333", 25, Gender.W, "류라해", "edu-image014.jpg", "이화여자", "대학교", "사이버보안학과", "1~3년", "CMC에서 만남", "착함", "자기관리, 귀여워, 차분해", "자기 일을 진짜 책임감 있게 잘하고 주변을 늘 먼저 생각하는 친구야", "서울시 마포구", "1병", 155, "내친소 사용하기", "profile-001-01.png,profile-001-02.png,profile-001-03.png", "반갑습니다 내친소 여러분!", "ESTJ", "열정적인, 상냥한, 섬세한", "기독교", "비흡연자", "같이 취미를 즐길 수 있는 연애를 하고 싶어"), - Arrays.asList("01022244444", 25, Gender.W, "민예지", "edu-image015.jpg", "이화여자", "대학교", "국어국문학과", "3~5년", "CMC에서 만남", "착함", "자기관리, 귀여워, 차분해", "자기 일을 진짜 책임감 있게 잘하고 주변을 늘 먼저 생각하는 친구야", "서울시 마포구", "1병", 150, "내친소 사용하기", "profile-001-01.png,profile-001-02.png,profile-001-03.png", "반갑습니다 내친소 여러분!", "INFJ", "열정적인, 상냥한, 섬세한", "무교", "비흡연자", "같이 취미를 즐길 수 있는 연애를 하고 싶어"), - Arrays.asList("01022255555", 25, Gender.W, "류유주", "edu-image016.jpg", "한국", "고등학교", "공학", "1~3년", "CMC에서 만남", "착함", "자기관리, 귀여워, 차분해", "자기 일을 진짜 책임감 있게 잘하고 주변을 늘 먼저 생각하는 친구야", "서울시 마포구", "1병", 174, "내친소 사용하기", "profile-001-01.png,profile-001-02.png,profile-001-03.png", "반갑습니다 내친소 여러분!", "INTP", "열정적인, 상냥한, 섬세한", "기독교", "비흡연자", "같이 취미를 즐길 수 있는 연애를 하고 싶어"), - Arrays.asList("01022266666", 25, Gender.W, "임혜서", "edu-image017.jpg", "서울", "대학원", "법학과", "1~3년", "CMC에서 만남", "착함", "자기관리, 귀여워, 차분해", "자기 일을 진짜 책임감 있게 잘하고 주변을 늘 먼저 생각하는 친구야", "서울시 마포구", "1병", 172, "내친소 사용하기", "profile-001-01.png,profile-001-02.png,profile-001-03.png", "반갑습니다 내친소 여러분!", "ESTJ", "열정적인, 상냥한, 섬세한", "불교", "비흡연자", "같이 취미를 즐길 수 있는 연애를 하고 싶어"), - Arrays.asList("01022277777", 25, Gender.W, "임한하", "edu-image018.jpg", "서울", "대학교", "의상학과", "3~5년", "CMC에서 만남", "착함", "자기관리, 귀여워, 차분해", "자기 일을 진짜 책임감 있게 잘하고 주변을 늘 먼저 생각하는 친구야", "서울시 마포구", "1병", 168, "내친소 사용하기", "profile-001-01.png,profile-001-02.png,profile-001-03.png", "반갑습니다 내친소 여러분!", "ENTP", "열정적인, 상냥한, 섬세한", "무교", "비흡연자", "같이 취미를 즐길 수 있는 연애를 하고 싶어"), - Arrays.asList("01022288888", 25, Gender.W, "권민영", "edu-image019.jpg", "고려", "대학교", "의학", "1~3년", "CMC에서 만남", "착함", "자기관리, 귀여워, 차분해", "자기 일을 진짜 책임감 있게 잘하고 주변을 늘 먼저 생각하는 친구야", "서울시 마포구", "1병", 175, "내친소 사용하기", "profile-001-01.png,profile-001-02.png,profile-001-03.png", "반갑습니다 내친소 여러분!", "ESFJ", "열정적인, 상냥한, 섬세한", "무교", "비흡연자", "같이 취미를 즐길 수 있는 연애를 하고 싶어"), - Arrays.asList("01022299999", 25, Gender.W, "진하수", "edu-image020.jpg", "연세", "대학교", "기계공학과", "1~3년", "CMC에서 만남", "착함", "자기관리, 귀여워, 차분해", "자기 일을 진짜 책임감 있게 잘하고 주변을 늘 먼저 생각하는 친구야", "서울시 마포구", "1병", 163, "내친소 사용하기", "profile-001-01.png,profile-001-02.png,profile-001-03.png", "반갑습니다 내친소 여러분!", "ESTJ", "열정적인, 상냥한, 섬세한", "무교", "비흡연자", "같이 취미를 즐길 수 있는 연애를 하고 싶어") + Arrays.asList("01011111111", 25, Gender.M, "허시준", "edu-image001.jpg", "서강", "대학교", "컴퓨터공학과", "1~3년", "CMC에서 만남", "착함", "\"패션센스 \uD83E\uDDE5\", \"사랑꾼 \uD83D\uDC97\", \"애교쟁이 \uD83D\uDE18\"", "자기 일을 진짜 책임감 있게 잘하고 주변을 늘 먼저 생각하는 친구야", "서울시 마포구", "1병", 180, "내친소 사용하기", "profile-001-01.png,profile-001-02.png,profile-001-03.png", "반갑습니다 내친소 여러분!", "ESTJ", "열정적인 \uD83D\uDD25,지적인 \uD83E\uDDD0,상냥한 ☺️", "무교", "비흡연자", "같이 취미를 즐길 수 있는 연애를 하고 싶어"), + Arrays.asList("01012222222", 26, Gender.M, "민성진", "edu-image002.jpg", "한국", "고등학교", "자동차정비", "1~3년", "CMC에서 만남", "착함", "패션센스 \uD83E\uDDE5,사랑꾼 \uD83D\uDC97,애교쟁이 \uD83D\uDE18", "자기 일을 진짜 책임감 있게 잘하고 주변을 늘 먼저 생각하는 친구야", "서울시 마포구", "1병", 185, "내친소 사용하기", "profile-001-01.png,profile-001-02.png,profile-001-03.png", "반갑습니다 내친소 여러분!", "INFP", "열정적인 \uD83D\uDD25,지적인 \uD83E\uDDD0,상냥한 ☺️", "무교", "비흡연자", "같이 취미를 즐길 수 있는 연애를 하고 싶어"), + Arrays.asList("01013333333", 27, Gender.M, "김상혁", "edu-image003.jpg", "서울", "대학원", "인공지능공학", "1~3년", "CMC에서 만남", "착함", "패션센스 \uD83E\uDDE5,사랑꾼 \uD83D\uDC97,애교쟁이 \uD83D\uDE18", "자기 일을 진짜 책임감 있게 잘하고 주변을 늘 먼저 생각하는 친구야", "서울시 마포구", "1병", 182, "내친소 사용하기", "profile-001-01.png,profile-001-02.png,profile-001-03.png", "반갑습니다 내친소 여러분!", "ESTJ", "열정적인 \uD83D\uDD25,지적인 \uD83E\uDDD0,상냥한 ☺️", "기독교", "비흡연자", "같이 취미를 즐길 수 있는 연애를 하고 싶어"), + Arrays.asList("01014444444", 28, Gender.M, "권영성", "edu-image004.jpg", "홍익", "대학교", "시각디자인학과", "1~3년", "CMC에서 만남", "착함", "패션센스 \uD83E\uDDE5,사랑꾼 \uD83D\uDC97,애교쟁이 \uD83D\uDE18", "자기 일을 진짜 책임감 있게 잘하고 주변을 늘 먼저 생각하는 친구야", "서울시 마포구", "1병", 183, "내친소 사용하기", "profile-001-01.png,profile-001-02.png,profile-001-03.png", "반갑습니다 내친소 여러분!", "INFJ", "열정적인 \uD83D\uDD25,지적인 \uD83E\uDDD0,상냥한 ☺️", "불교", "비흡연자", "같이 취미를 즐길 수 있는 연애를 하고 싶어"), + Arrays.asList("01015555555", 29, Gender.M, "배규빈", "edu-image005.jpg", "한성", "고등학교", "상업", "3~5년", "CMC에서 만남", "착함", "패션센스 \uD83E\uDDE5,사랑꾼 \uD83D\uDC97,애교쟁이 \uD83D\uDE18", "자기 일을 진짜 책임감 있게 잘하고 주변을 늘 먼저 생각하는 친구야", "서울시 마포구", "1병", 178, "내친소 사용하기", "profile-001-01.png,profile-001-02.png,profile-001-03.png", "반갑습니다 내친소 여러분!", "ESTJ", "열정적인 \uD83D\uDD25,지적인 \uD83E\uDDD0,상냥한 ☺️", "무교", "비흡연자", "같이 취미를 즐길 수 있는 연애를 하고 싶어"), + Arrays.asList("01016666666", 30, Gender.M, "권민기", "edu-image006.jpg", "서울", "고등학교", "디자인", "3~5년", "CMC에서 만남", "착함", "패션센스 \uD83E\uDDE5,사랑꾼 \uD83D\uDC97,애교쟁이 \uD83D\uDE18", "자기 일을 진짜 책임감 있게 잘하고 주변을 늘 먼저 생각하는 친구야", "서울시 마포구", "1병", 172, "내친소 사용하기", "profile-001-01.png,profile-001-02.png,profile-001-03.png", "반갑습니다 내친소 여러분!", "ESFJ", "열정적인 \uD83D\uDD25,지적인 \uD83E\uDDD0,상냥한 ☺️", "무교", "비흡연자", "같이 취미를 즐길 수 있는 연애를 하고 싶어"), + Arrays.asList("01017777777", 31, Gender.M, "김민성", "edu-image007.jpg", "연세", "대학원", "영어영문학과", "1~3년", "CMC에서 만남", "착함", "패션센스 \uD83E\uDDE5,사랑꾼 \uD83D\uDC97,애교쟁이 \uD83D\uDE18", "자기 일을 진짜 책임감 있게 잘하고 주변을 늘 먼저 생각하는 친구야", "서울시 마포구", "1병", 173, "내친소 사용하기", "profile-001-01.png,profile-001-02.png,profile-001-03.png", "반갑습니다 내친소 여러분!", "ENFP", "열정적인 \uD83D\uDD25,지적인 \uD83E\uDDD0,상냥한 ☺️", "기독교", "비흡연자", "같이 취미를 즐길 수 있는 연애를 하고 싶어"), + Arrays.asList("01018888888", 32, Gender.M, "임정혁", "edu-image008.jpg", "연세", "대학교", "전기전자공학과", "1~3년", "CMC에서 만남", "착함", "패션센스 \uD83E\uDDE5,사랑꾼 \uD83D\uDC97,애교쟁이 \uD83D\uDE18", "자기 일을 진짜 책임감 있게 잘하고 주변을 늘 먼저 생각하는 친구야", "서울시 마포구", "1병", 175, "내친소 사용하기", "profile-001-01.png,profile-001-02.png,profile-001-03.png", "반갑습니다 내친소 여러분!", "ESTJ", "열정적인 \uD83D\uDD25,지적인 \uD83E\uDDD0,상냥한 ☺️", "무교", "비흡연자", "같이 취미를 즐길 수 있는 연애를 하고 싶어"), + Arrays.asList("01019999999", 33, Gender.M, "성재오", "edu-image009.jpg", "이대부속", "고등학교", "공학", "1~3년", "CMC에서 만남", "착함", "패션센스 \uD83E\uDDE5,사랑꾼 \uD83D\uDC97,애교쟁이 \uD83D\uDE18", "자기 일을 진짜 책임감 있게 잘하고 주변을 늘 먼저 생각하는 친구야", "서울시 마포구", "1병", 168, "내친소 사용하기", "profile-001-01.png,profile-001-02.png,profile-001-03.png", "반갑습니다 내친소 여러분!", "ESTJ", "열정적인 \uD83D\uDD25,지적인 \uD83E\uDDD0,상냥한 ☺️", "무교", "비흡연자", "같이 취미를 즐길 수 있는 연애를 하고 싶어"), + Arrays.asList("01010000000", 25, Gender.M, "차재훈", "edu-image010.jpg", "국민", "대학교", "미디어학과", "1~3년", "CMC에서 만남", "착함", "패션센스 \uD83E\uDDE5,사랑꾼 \uD83D\uDC97,애교쟁이 \uD83D\uDE18", "자기 일을 진짜 책임감 있게 잘하고 주변을 늘 먼저 생각하는 친구야", "서울시 마포구", "1병", 176, "내친소 사용하기", "profile-001-01.png,profile-001-02.png,profile-001-03.png", "반갑습니다 내친소 여러분!", "ESTP", "열정적인 \uD83D\uDD25,지적인 \uD83E\uDDD0,상냥한 ☺️", "무교", "비흡연자", "같이 취미를 즐길 수 있는 연애를 하고 싶어"), + + Arrays.asList("01022200000", 25, Gender.W, "민장효", "edu-image011.jpg", "서강", "대학원", "물류학과", "1~3년", "CMC에서 만남", "착함", "패션센스 \uD83E\uDDE5,사랑꾼 \uD83D\uDC97,애교쟁이 \uD83D\uDE18", "자기 일을 진짜 책임감 있게 잘하고 주변을 늘 먼저 생각하는 친구야", "서울시 마포구", "1병", 160, "내친소 사용하기", "profile-001-01.png,profile-001-02.png,profile-001-03.png", "반갑습니다 내친소 여러분!", "INFP", "열정적인 \uD83D\uDD25,지적인 \uD83E\uDDD0,상냥한 ☺️", "무교", "비흡연자", "같이 취미를 즐길 수 있는 연애를 하고 싶어"), + Arrays.asList("01022211111", 25, Gender.W, "김민서", "edu-image012.jpg", "홍익", "대학교", "조소과", "1~3년", "CMC에서 만남", "착함", "패션센스 \uD83E\uDDE5,사랑꾼 \uD83D\uDC97,애교쟁이 \uD83D\uDE18", "자기 일을 진짜 책임감 있게 잘하고 주변을 늘 먼저 생각하는 친구야", "서울시 마포구", "1병", 162, "내친소 사용하기", "profile-001-01.png,profile-001-02.png,profile-001-03.png", "반갑습니다 내친소 여러분!", "ESTJ", "열정적인 \uD83D\uDD25,지적인 \uD83E\uDDD0,상냥한 ☺️", "무교", "비흡연자", "같이 취미를 즐길 수 있는 연애를 하고 싶어"), + Arrays.asList("01022222222", 25, Gender.W, "노혜지", "edu-image013.jpg", "한국", "고등학교", "디자인", "1~3년", "CMC에서 만남", "착함", "패션센스 \uD83E\uDDE5,사랑꾼 \uD83D\uDC97,애교쟁이 \uD83D\uDE18", "자기 일을 진짜 책임감 있게 잘하고 주변을 늘 먼저 생각하는 친구야", "서울시 마포구", "1병", 165, "내친소 사용하기", "profile-001-01.png,profile-001-02.png,profile-001-03.png", "반갑습니다 내친소 여러분!", "ENFP", "열정적인 \uD83D\uDD25,지적인 \uD83E\uDDD0,상냥한 ☺️", "기독교", "비흡연자", "같이 취미를 즐길 수 있는 연애를 하고 싶어"), + Arrays.asList("01022233333", 25, Gender.W, "류라해", "edu-image014.jpg", "이화여자", "대학교", "사이버보안학과", "1~3년", "CMC에서 만남", "착함", "패션센스 \uD83E\uDDE5,사랑꾼 \uD83D\uDC97,애교쟁이 \uD83D\uDE18", "자기 일을 진짜 책임감 있게 잘하고 주변을 늘 먼저 생각하는 친구야", "서울시 마포구", "1병", 155, "내친소 사용하기", "profile-001-01.png,profile-001-02.png,profile-001-03.png", "반갑습니다 내친소 여러분!", "ESTJ", "열정적인 \uD83D\uDD25,지적인 \uD83E\uDDD0,상냥한 ☺️", "기독교", "비흡연자", "같이 취미를 즐길 수 있는 연애를 하고 싶어"), + Arrays.asList("01022244444", 25, Gender.W, "민예지", "edu-image015.jpg", "이화여자", "대학교", "국어국문학과", "3~5년", "CMC에서 만남", "착함", "패션센스 \uD83E\uDDE5,사랑꾼 \uD83D\uDC97,애교쟁이 \uD83D\uDE18", "자기 일을 진짜 책임감 있게 잘하고 주변을 늘 먼저 생각하는 친구야", "서울시 마포구", "1병", 150, "내친소 사용하기", "profile-001-01.png,profile-001-02.png,profile-001-03.png", "반갑습니다 내친소 여러분!", "INFJ", "열정적인 \uD83D\uDD25,지적인 \uD83E\uDDD0,상냥한 ☺️", "무교", "비흡연자", "같이 취미를 즐길 수 있는 연애를 하고 싶어"), + Arrays.asList("01022255555", 25, Gender.W, "류유주", "edu-image016.jpg", "한국", "고등학교", "공학", "1~3년", "CMC에서 만남", "착함", "패션센스 \uD83E\uDDE5,사랑꾼 \uD83D\uDC97,애교쟁이 \uD83D\uDE18", "자기 일을 진짜 책임감 있게 잘하고 주변을 늘 먼저 생각하는 친구야", "서울시 마포구", "1병", 174, "내친소 사용하기", "profile-001-01.png,profile-001-02.png,profile-001-03.png", "반갑습니다 내친소 여러분!", "INTP", "열정적인 \uD83D\uDD25,지적인 \uD83E\uDDD0,상냥한 ☺️", "기독교", "비흡연자", "같이 취미를 즐길 수 있는 연애를 하고 싶어"), + Arrays.asList("01022266666", 25, Gender.W, "임혜서", "edu-image017.jpg", "서울", "대학원", "법학과", "1~3년", "CMC에서 만남", "착함", "패션센스 \uD83E\uDDE5,사랑꾼 \uD83D\uDC97,애교쟁이 \uD83D\uDE18", "자기 일을 진짜 책임감 있게 잘하고 주변을 늘 먼저 생각하는 친구야", "서울시 마포구", "1병", 172, "내친소 사용하기", "profile-001-01.png,profile-001-02.png,profile-001-03.png", "반갑습니다 내친소 여러분!", "ESTJ", "열정적인 \uD83D\uDD25,지적인 \uD83E\uDDD0,상냥한 ☺️", "불교", "비흡연자", "같이 취미를 즐길 수 있는 연애를 하고 싶어"), + Arrays.asList("01022277777", 25, Gender.W, "임한하", "edu-image018.jpg", "서울", "대학교", "의상학과", "3~5년", "CMC에서 만남", "착함", "패션센스 \uD83E\uDDE5,사랑꾼 \uD83D\uDC97,애교쟁이 \uD83D\uDE18", "자기 일을 진짜 책임감 있게 잘하고 주변을 늘 먼저 생각하는 친구야", "서울시 마포구", "1병", 168, "내친소 사용하기", "profile-001-01.png,profile-001-02.png,profile-001-03.png", "반갑습니다 내친소 여러분!", "ENTP", "열정적인 \uD83D\uDD25,지적인 \uD83E\uDDD0,상냥한 ☺️", "무교", "비흡연자", "같이 취미를 즐길 수 있는 연애를 하고 싶어"), + Arrays.asList("01022288888", 25, Gender.W, "권민영", "edu-image019.jpg", "고려", "대학교", "의학", "1~3년", "CMC에서 만남", "착함", "패션센스 \uD83E\uDDE5,사랑꾼 \uD83D\uDC97,애교쟁이 \uD83D\uDE18", "자기 일을 진짜 책임감 있게 잘하고 주변을 늘 먼저 생각하는 친구야", "서울시 마포구", "1병", 175, "내친소 사용하기", "profile-001-01.png,profile-001-02.png,profile-001-03.png", "반갑습니다 내친소 여러분!", "ESFJ", "열정적인 \uD83D\uDD25,지적인 \uD83E\uDDD0,상냥한 ☺️", "무교", "비흡연자", "같이 취미를 즐길 수 있는 연애를 하고 싶어"), + Arrays.asList("01022299999", 25, Gender.W, "진하수", "edu-image020.jpg", "연세", "대학교", "기계공학과", "1~3년", "CMC에서 만남", "착함", "패션센스 \uD83E\uDDE5,사랑꾼 \uD83D\uDC97,애교쟁이 \uD83D\uDE18", "자기 일을 진짜 책임감 있게 잘하고 주변을 늘 먼저 생각하는 친구야", "서울시 마포구", "1병", 163, "내친소 사용하기", "profile-001-01.png,profile-001-02.png,profile-001-03.png", "반갑습니다 내친소 여러분!", "ESTJ", "열정적인 \uD83D\uDD25,지적인 \uD83E\uDDD0,상냥한 ☺️", "무교", "비흡연자", "같이 취미를 즐길 수 있는 연애를 하고 싶어") ); String accessToken = null; @@ -437,8 +434,7 @@ public CommonApiResponse createMultipleMembers() { .name((String) info.get(3)) .period((String) info.get(8)) .meet((String) info.get(9)) - .personality((String) info.get(10)) - .appeal((String) info.get(11)) + .appeals(List.of(StringUtils.split((String) info.get(11), ","))) .appealDetail((String) info.get(12)) .build()); @@ -454,7 +450,7 @@ public CommonApiResponse createMultipleMembers() { .image_accepted(true) .introduce((String) info.get(18)) .mbti((String) info.get(19)) - .personality((String) info.get(20)) + .personalities((String) info.get(20)) .religion((String) info.get(21)) .smoke((String) info.get(22)) .style((String) info.get(23)) diff --git a/src/main/java/com/tikitaka/naechinso/domain/card/dto/CardOppositeMemberProfileResponseDTO.java b/src/main/java/com/tikitaka/naechinso/domain/card/dto/CardOppositeMemberProfileResponseDTO.java index 234582c..e6ada8e 100644 --- a/src/main/java/com/tikitaka/naechinso/domain/card/dto/CardOppositeMemberProfileResponseDTO.java +++ b/src/main/java/com/tikitaka/naechinso/domain/card/dto/CardOppositeMemberProfileResponseDTO.java @@ -33,7 +33,7 @@ public class CardOppositeMemberProfileResponseDTO { private String eduMajor; private String eduLevel; - private String personality; + private List personalities; private String religion; private int height; private String smoke; @@ -54,7 +54,7 @@ public class CardOppositeMemberProfileResponseDTO { public static class Recommendation { private String name; private Gender gender; - private String appeal; + private List appeals; private String jobName; private String jobPart; @@ -72,7 +72,7 @@ public static Recommendation of(Recommend recommend) { return Recommendation.builder() .name(CustomStringUtil.hideName(recommend.getSenderName())) .gender(recommend.getSenderGender()) - .appeal(recommend.getReceiverAppeal()) + .appeals(recommend.getReceiverAppeals()) .appealDetail(recommend.getReceiverAppealDetail()) .eduName(sender.getEduName()) .eduMajor(sender.getEduMajor()) @@ -113,7 +113,7 @@ public static CardOppositeMemberProfileResponseDTO of(Member member) { .eduMajor(member.getEduMajor()) .eduLevel(member.getEduLevel()) .gender(member.getGender()) - .personality(detail.getPersonality()) + .personalities(detail.getPersonalities()) .religion(detail.getReligion()) .height(detail.getHeight()) .smoke(detail.getSmoke()) diff --git a/src/main/java/com/tikitaka/naechinso/domain/card/dto/CardThumbnailResponseDTO.java b/src/main/java/com/tikitaka/naechinso/domain/card/dto/CardThumbnailResponseDTO.java index ae66bbe..901d7b0 100644 --- a/src/main/java/com/tikitaka/naechinso/domain/card/dto/CardThumbnailResponseDTO.java +++ b/src/main/java/com/tikitaka/naechinso/domain/card/dto/CardThumbnailResponseDTO.java @@ -51,7 +51,7 @@ public class CardThumbnailResponseDTO { private static class Recommendation { private String name; private Gender gender; - private String appeal; + private List appeals; private String jobName; private String jobPart; @@ -92,7 +92,7 @@ public static CardThumbnailResponseDTO of(Card card, Member targetMember) { .recommend(Recommendation.builder() .name(dto.getRecommend().getName()) .gender(dto.getRecommend().getGender()) - .appeal(dto.getRecommend().getAppeal()) + .appeals(dto.getRecommend().getAppeals()) .jobName(dto.getRecommend().getJobName()) .jobLocation(dto.getRecommend().getJobLocation()) .jobPart(dto.getRecommend().getJobPart()) diff --git a/src/main/java/com/tikitaka/naechinso/domain/match/dto/MatchBasicProfileResponseDTO.java b/src/main/java/com/tikitaka/naechinso/domain/match/dto/MatchBasicProfileResponseDTO.java index aa8186b..0133d27 100644 --- a/src/main/java/com/tikitaka/naechinso/domain/match/dto/MatchBasicProfileResponseDTO.java +++ b/src/main/java/com/tikitaka/naechinso/domain/match/dto/MatchBasicProfileResponseDTO.java @@ -36,7 +36,7 @@ public class MatchBasicProfileResponseDTO { private String eduMajor; private String eduLevel; - private String personality; + private List personalities; private String religion; private int height; private String smoke; @@ -57,7 +57,7 @@ public class MatchBasicProfileResponseDTO { public static class Recommendation { private String name; private Gender gender; - private String appeal; + private List appeals; private String jobName; private String jobPart; @@ -99,7 +99,7 @@ public static MatchBasicProfileResponseDTO of(Member targetMember) { .eduMajor(targetMember.getEduMajor()) .eduLevel(targetMember.getEduLevel()) .gender(targetMember.getGender()) - .personality(detail.getPersonality()) + .personalities(detail.getPersonalities()) .religion(detail.getReligion()) .height(detail.getHeight()) .smoke(detail.getSmoke()) @@ -111,7 +111,7 @@ public static MatchBasicProfileResponseDTO of(Member targetMember) { .recommend(Recommendation.builder() .name(CustomStringUtil.hideName(recommend.getSenderName())) .gender(recommend.getSenderGender()) - .appeal(recommend.getReceiverAppeal()) + .appeals(recommend.getReceiverAppeals()) .appealDetail(recommend.getReceiverAppealDetail()) .eduName(recommend.getSender().getEduName()) .eduMajor(recommend.getSender().getEduMajor()) diff --git a/src/main/java/com/tikitaka/naechinso/domain/match/dto/MatchOpenProfileResponseDTO.java b/src/main/java/com/tikitaka/naechinso/domain/match/dto/MatchOpenProfileResponseDTO.java index 2d23c11..456d621 100644 --- a/src/main/java/com/tikitaka/naechinso/domain/match/dto/MatchOpenProfileResponseDTO.java +++ b/src/main/java/com/tikitaka/naechinso/domain/match/dto/MatchOpenProfileResponseDTO.java @@ -38,7 +38,7 @@ public class MatchOpenProfileResponseDTO { private String eduMajor; private String eduLevel; - private String personality; + private List personalities; private String religion; private int height; private String smoke; @@ -59,7 +59,7 @@ public class MatchOpenProfileResponseDTO { public static class Recommendation { private String name; private Gender gender; - private String appeal; + private List appeals; private String jobName; private String jobPart; @@ -102,7 +102,7 @@ public static MatchOpenProfileResponseDTO of(Member targetMember) { .eduMajor(targetMember.getEduMajor()) .eduLevel(targetMember.getEduLevel()) .gender(targetMember.getGender()) - .personality(detail.getPersonality()) + .personalities(detail.getPersonalities()) .religion(detail.getReligion()) .height(detail.getHeight()) .smoke(detail.getSmoke()) @@ -114,7 +114,7 @@ public static MatchOpenProfileResponseDTO of(Member targetMember) { .recommend(Recommendation.builder() .name(CustomStringUtil.hideName(recommend.getSenderName())) .gender(recommend.getSenderGender()) - .appeal(recommend.getReceiverAppeal()) + .appeals(recommend.getReceiverAppeals()) .appealDetail(recommend.getReceiverAppealDetail()) .eduName(recommend.getSender().getEduName()) .eduMajor(recommend.getSender().getEduMajor()) diff --git a/src/main/java/com/tikitaka/naechinso/domain/match/dto/MatchThumbnailResponseDTO.java b/src/main/java/com/tikitaka/naechinso/domain/match/dto/MatchThumbnailResponseDTO.java index 134a579..4e93279 100644 --- a/src/main/java/com/tikitaka/naechinso/domain/match/dto/MatchThumbnailResponseDTO.java +++ b/src/main/java/com/tikitaka/naechinso/domain/match/dto/MatchThumbnailResponseDTO.java @@ -54,7 +54,7 @@ public class MatchThumbnailResponseDTO { private static class Recommendation { private String name; private Gender gender; - private String appeal; + private List appeals; private String jobName; private String jobPart; @@ -100,7 +100,7 @@ public static MatchThumbnailResponseDTO of(Match match, Member member) { .recommend(Recommendation.builder() .name(dto.getRecommend().getName()) .gender(dto.getRecommend().getGender()) - .appeal(dto.getRecommend().getAppeal()) + .appeals(dto.getRecommend().getAppeals()) .jobName(dto.getRecommend().getJobName()) .jobLocation(dto.getRecommend().getJobLocation()) .jobPart(dto.getRecommend().getJobPart()) diff --git a/src/main/java/com/tikitaka/naechinso/domain/member/dto/MemberDetailJoinRequestDTO.java b/src/main/java/com/tikitaka/naechinso/domain/member/dto/MemberDetailJoinRequestDTO.java index da52792..bfb0f76 100644 --- a/src/main/java/com/tikitaka/naechinso/domain/member/dto/MemberDetailJoinRequestDTO.java +++ b/src/main/java/com/tikitaka/naechinso/domain/member/dto/MemberDetailJoinRequestDTO.java @@ -57,9 +57,14 @@ public class MemberDetailJoinRequestDTO { @Length(max = 4, message = "올바른 MBTI 정보를 입력하세요") private String mbti; - @ApiModelProperty(example = "직관적") - @NotBlank(message = "성격 정보를 입력해야 합니다") - private String personality; +// @ApiModelProperty(example = "직관적") +// @NotBlank(message = "성격 정보를 입력해야 합니다") +// private String personality; + + @ApiModelProperty(example = "[\"열정적인 \uD83D\uDD25\", \"지적인 \uD83E\uDDD0\", \"상냥한 ☺️\"]") + @Size(min = 3, max = 3, message = "성격 키워드 3개를 입력해야 합니다") + @NotNull + private List personalities; @ApiModelProperty(example = "반갑습니다") @NotBlank(message = "자기 소개를 입력해야 합니다") diff --git a/src/main/java/com/tikitaka/naechinso/domain/member/dto/MemberDetailResponseDTO.java b/src/main/java/com/tikitaka/naechinso/domain/member/dto/MemberDetailResponseDTO.java index 284d2a7..7323381 100644 --- a/src/main/java/com/tikitaka/naechinso/domain/member/dto/MemberDetailResponseDTO.java +++ b/src/main/java/com/tikitaka/naechinso/domain/member/dto/MemberDetailResponseDTO.java @@ -45,7 +45,7 @@ public class MemberDetailResponseDTO { private String mbti; - private String personality; + private List personalities; private String introduce; @@ -90,11 +90,12 @@ private static MemberDetailResponseDTO buildDetail(MemberDetail detail) { .drink(detail.getDrink()) .smoke(detail.getSmoke()) .mbti(detail.getMbti()) - .personality(detail.getPersonality()) + .personalities(detail.getPersonalities()) .introduce(detail.getIntroduce()) .hobby(detail.getHobby()) .style(detail.getStyle()) .images(detail.getImages()) + .point(0L) .build(); } diff --git a/src/main/java/com/tikitaka/naechinso/domain/member/dto/MemberDetailUpdateRequestDTO.java b/src/main/java/com/tikitaka/naechinso/domain/member/dto/MemberDetailUpdateRequestDTO.java index 15f65cf..6721473 100644 --- a/src/main/java/com/tikitaka/naechinso/domain/member/dto/MemberDetailUpdateRequestDTO.java +++ b/src/main/java/com/tikitaka/naechinso/domain/member/dto/MemberDetailUpdateRequestDTO.java @@ -43,9 +43,10 @@ public class MemberDetailUpdateRequestDTO { @Length(max = 4, message = "올바른 MBTI 정보를 입력하세요") private String mbti; - @ApiModelProperty(example = "직관적") - @NotBlank(message = "성격 정보를 입력해야 합니다") - private String personality; + @ApiModelProperty(example = "[\"열정적인 \uD83D\uDD25\", \"지적인 \uD83E\uDDD0\", \"상냥한 ☺️\"]") + @Size(min = 3, max = 3, message = "성격 키워드 3개를 입력해야 합니다") + @NotNull + private List personalities; @ApiModelProperty(example = "반갑습니다") @NotBlank(message = "자기 소개를 입력해야 합니다") diff --git a/src/main/java/com/tikitaka/naechinso/domain/member/dto/MemberOppositeProfileResponseDTO.java b/src/main/java/com/tikitaka/naechinso/domain/member/dto/MemberOppositeProfileResponseDTO.java index 98ed25f..e7dd51b 100644 --- a/src/main/java/com/tikitaka/naechinso/domain/member/dto/MemberOppositeProfileResponseDTO.java +++ b/src/main/java/com/tikitaka/naechinso/domain/member/dto/MemberOppositeProfileResponseDTO.java @@ -40,7 +40,7 @@ public class MemberOppositeProfileResponseDTO { private String eduMajor; private String eduLevel; - private String personality; + private List personalities; private String religion; private int height; private String smoke; @@ -61,7 +61,7 @@ public class MemberOppositeProfileResponseDTO { public static class Recommendation { private String name; private Gender gender; - private String appeal; + private List appeals; private String jobName; private String jobPart; @@ -79,7 +79,7 @@ public static Recommendation of(Recommend recommend) { return Recommendation.builder() .name(CustomStringUtil.hideName(recommend.getSenderName())) .gender(recommend.getSenderGender()) - .appeal(recommend.getReceiverAppeal()) + .appeals(recommend.getReceiverAppeals()) .appealDetail(recommend.getReceiverAppealDetail()) .eduName(sender.getEduName()) .eduMajor(sender.getEduMajor()) @@ -120,7 +120,7 @@ public static MemberOppositeProfileResponseDTO of(Member member) { .eduMajor(member.getEduMajor()) .eduLevel(member.getEduLevel()) .gender(member.getGender()) - .personality(detail.getPersonality()) + .personalities(detail.getPersonalities()) .religion(detail.getReligion()) .height(detail.getHeight()) .smoke(detail.getSmoke()) diff --git a/src/main/java/com/tikitaka/naechinso/domain/member/entity/MemberDetail.java b/src/main/java/com/tikitaka/naechinso/domain/member/entity/MemberDetail.java index 6021afe..e1e3a6f 100644 --- a/src/main/java/com/tikitaka/naechinso/domain/member/entity/MemberDetail.java +++ b/src/main/java/com/tikitaka/naechinso/domain/member/entity/MemberDetail.java @@ -50,8 +50,8 @@ public class MemberDetail extends BaseEntity { @Builder.Default private String mbti = ""; - @Column(name = "mem_personality") - private String personality; + @Column(name = "mem_personalities") + private String personalities; @Column(name = "mem_introduce") @Builder.Default @@ -93,7 +93,7 @@ public static MemberDetail of(MemberDetailJoinRequestDTO dto) { .drink(dto.getDrink()) .smoke(dto.getSmoke()) .mbti(dto.getMbti()) - .personality(dto.getPersonality()) + .personalities(StringUtils.join(dto.getPersonalities(), ",")) .introduce(dto.getIntroduce()) .hobby(dto.getHobby()) .style(dto.getStyle()) @@ -109,7 +109,7 @@ public static MemberDetail of(Member member, MemberDetailJoinRequestDTO dto) { .drink(dto.getDrink()) .smoke(dto.getSmoke()) .mbti(dto.getMbti()) - .personality(dto.getPersonality()) + .personalities(StringUtils.join(dto.getPersonalities(), ",")) .introduce(dto.getIntroduce()) .hobby(dto.getHobby()) .style(dto.getStyle()) @@ -118,6 +118,13 @@ public static MemberDetail of(Member member, MemberDetailJoinRequestDTO dto) { .build(); } + public List getPersonalities(){ + if (this.personalities != null) { + return List.of(this.personalities.split(",")); + } + return List.of(); + } + public List getImages() { if (this.images != null) { return List.of(this.images.split(",")); diff --git a/src/main/java/com/tikitaka/naechinso/domain/recommend/RecommendService.java b/src/main/java/com/tikitaka/naechinso/domain/recommend/RecommendService.java index e38840c..1d7ffd4 100644 --- a/src/main/java/com/tikitaka/naechinso/domain/recommend/RecommendService.java +++ b/src/main/java/com/tikitaka/naechinso/domain/recommend/RecommendService.java @@ -11,6 +11,7 @@ import com.tikitaka.naechinso.global.error.exception.NotFoundException; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; +import org.apache.commons.lang3.StringUtils; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; @@ -82,10 +83,9 @@ public RecommendResponseDTO createRecommend(Member authMember, RecommendBySender .receiverName(dto.getName()) .receiverAge(dto.getAge()) .receiverGender(dto.getGender()) - .receiverAppeal(dto.getAppeal()) + .receiverAppeals(StringUtils.join(dto.getAppeals(), ",")) .receiverAppealDetail(dto.getAppealDetail()) .receiverMeet(dto.getMeet()) - .receiverPersonality(dto.getPersonality()) .receiverPeriod(dto.getPeriod()) .build(); diff --git a/src/main/java/com/tikitaka/naechinso/domain/recommend/dto/RecommendAcceptRequestDTO.java b/src/main/java/com/tikitaka/naechinso/domain/recommend/dto/RecommendAcceptRequestDTO.java index 82be387..3395ded 100644 --- a/src/main/java/com/tikitaka/naechinso/domain/recommend/dto/RecommendAcceptRequestDTO.java +++ b/src/main/java/com/tikitaka/naechinso/domain/recommend/dto/RecommendAcceptRequestDTO.java @@ -7,6 +7,7 @@ import lombok.*; import javax.validation.constraints.*; +import java.util.List; @AllArgsConstructor @NoArgsConstructor @@ -19,13 +20,10 @@ public class RecommendAcceptRequestDTO { @NotBlank(message = "만나게 된 계기를 입력해주세요") private String meet; - @ApiModelProperty(example = "최고") - @NotBlank(message = "친구의 성격 키워드를 입력해주세요") - private String personality; - - @ApiModelProperty(example = "유머있는") - @NotBlank(message = "친구의 매력 키워드를 입력해주세요") - private String appeal; + @ApiModelProperty(example = "[\"패션센스 \uD83E\uDDE5\", \"사랑꾼 \uD83D\uDC97\", \"애교쟁이 \uD83D\uDE18\"]") + @Size(min = 3, max = 3, message = "매력 키워드 3개를 입력해야 합니다") + @NotNull + private List appeals; @ApiModelProperty(example = "짱짱짜짱 멋진 개발자입니다") @NotBlank(message = "친구의 자세한 매력을 입력해주세요") diff --git a/src/main/java/com/tikitaka/naechinso/domain/recommend/dto/RecommendBySenderRequestDTO.java b/src/main/java/com/tikitaka/naechinso/domain/recommend/dto/RecommendBySenderRequestDTO.java index 95b7249..3c46158 100644 --- a/src/main/java/com/tikitaka/naechinso/domain/recommend/dto/RecommendBySenderRequestDTO.java +++ b/src/main/java/com/tikitaka/naechinso/domain/recommend/dto/RecommendBySenderRequestDTO.java @@ -6,6 +6,7 @@ import lombok.*; import javax.validation.constraints.*; +import java.util.List; /** 가입하지 않은 멤버가 추천사를 써줄 때 요청 DTO * @author gengminy 221001 @@ -38,13 +39,10 @@ public class RecommendBySenderRequestDTO { @NotBlank(message = "만나게 된 계기를 입력해주세요") private String meet; - @ApiModelProperty(example = "최고") - @NotBlank(message = "친구의 성격 키워드를 입력해주세요") - private String personality; - - @ApiModelProperty(example = "짱") - @NotBlank(message = "친구의 매력을 입력해주세요") - private String appeal; + @ApiModelProperty(example = "[\"패션센스 \uD83E\uDDE5\", \"사랑꾼 \uD83D\uDC97\", \"애교쟁이 \uD83D\uDE18\"]") + @Size(min = 3, max = 3, message = "매력 키워드 3개를 입력해야 합니다") + @NotNull + private List appeals; @ApiModelProperty(example = "짱짱짜짱 멋진 개발자입니다") @NotBlank(message = "친구의 자세한 매력을 입력해주세요") diff --git a/src/main/java/com/tikitaka/naechinso/domain/recommend/dto/RecommendMemberAcceptAndUpdateRequestDTO.java b/src/main/java/com/tikitaka/naechinso/domain/recommend/dto/RecommendMemberAcceptAndUpdateRequestDTO.java index e8cc324..eefac82 100644 --- a/src/main/java/com/tikitaka/naechinso/domain/recommend/dto/RecommendMemberAcceptAndUpdateRequestDTO.java +++ b/src/main/java/com/tikitaka/naechinso/domain/recommend/dto/RecommendMemberAcceptAndUpdateRequestDTO.java @@ -6,6 +6,7 @@ import lombok.*; import javax.validation.constraints.*; +import java.util.List; @AllArgsConstructor @NoArgsConstructor @@ -36,13 +37,10 @@ public class RecommendMemberAcceptAndUpdateRequestDTO { @NotBlank(message = "만나게 된 계기를 입력해주세요") private String meet; - @ApiModelProperty(example = "최고") - @NotBlank(message = "친구의 성격 키워드를 입력해주세요") - private String personality; - - @ApiModelProperty(example = "짱") - @NotBlank(message = "친구의 매력 키워드를 입력해주세요") - private String appeal; + @ApiModelProperty(example = "[\"패션센스 \uD83E\uDDE5\", \"사랑꾼 \uD83D\uDC97\", \"애교쟁이 \uD83D\uDE18\"]") + @Size(min = 3, max = 3, message = "매력 키워드 3개를 입력해야 합니다") + @NotNull + private List appeals; @ApiModelProperty(example = "짱짱짜짱 멋진 개발자입니다") @NotBlank(message = "친구의 자세한 매력을 입력해주세요") diff --git a/src/main/java/com/tikitaka/naechinso/domain/recommend/dto/RecommendMemberAcceptRequestDTO.java b/src/main/java/com/tikitaka/naechinso/domain/recommend/dto/RecommendMemberAcceptRequestDTO.java index 27330e1..c026129 100644 --- a/src/main/java/com/tikitaka/naechinso/domain/recommend/dto/RecommendMemberAcceptRequestDTO.java +++ b/src/main/java/com/tikitaka/naechinso/domain/recommend/dto/RecommendMemberAcceptRequestDTO.java @@ -4,6 +4,7 @@ import lombok.*; import javax.validation.constraints.*; +import java.util.List; /** 내친소 회원이 다른 유저를 추천할 때 사용할 DTO * @author gengminy 221003 @@ -18,13 +19,10 @@ public class RecommendMemberAcceptRequestDTO { @NotBlank(message = "만나게 된 계기를 입력해주세요") private String meet; - @ApiModelProperty(example = "최고") - @NotBlank(message = "친구의 성격 키워드를 입력해주세요") - private String personality; - - @ApiModelProperty(example = "짱") - @NotBlank(message = "친구의 매력 키워드를 입력해주세요") - private String appeal; + @ApiModelProperty(example = "[\"패션센스 \uD83E\uDDE5\", \"사랑꾼 \uD83D\uDC97\", \"애교쟁이 \uD83D\uDE18\"]") + @Size(min = 3, max = 3, message = "매력 키워드 3개를 입력해야 합니다") + @NotNull + private List appeals; @ApiModelProperty(example = "짱짱짜짱 멋진 개발자입니다") @NotBlank(message = "친구의 자세한 매력을 입력해주세요") diff --git a/src/main/java/com/tikitaka/naechinso/domain/recommend/dto/RecommendResponseDTO.java b/src/main/java/com/tikitaka/naechinso/domain/recommend/dto/RecommendResponseDTO.java index b72cf5b..79e232b 100644 --- a/src/main/java/com/tikitaka/naechinso/domain/recommend/dto/RecommendResponseDTO.java +++ b/src/main/java/com/tikitaka/naechinso/domain/recommend/dto/RecommendResponseDTO.java @@ -4,6 +4,8 @@ import com.tikitaka.naechinso.domain.recommend.entity.Recommend; import lombok.*; +import java.util.List; + @AllArgsConstructor @NoArgsConstructor @Getter @@ -23,7 +25,7 @@ public class RecommendResponseDTO { private String meet; - private String appeal; + private List appeals; private String appealDetail; @@ -58,7 +60,7 @@ public static RecommendResponseDTO of(Recommend recommend) { .gender(recommend.getReceiverGender()) .age(recommend.getReceiverAge()) .meet(recommend.getReceiverMeet()) - .appeal(recommend.getReceiverAppeal()) + .appeals(recommend.getReceiverAppeals()) .appealDetail(recommend.getReceiverAppealDetail()) .period(recommend.getReceiverPeriod()) .build(); diff --git a/src/main/java/com/tikitaka/naechinso/domain/recommend/entity/Recommend.java b/src/main/java/com/tikitaka/naechinso/domain/recommend/entity/Recommend.java index f7f5d59..4d477d6 100644 --- a/src/main/java/com/tikitaka/naechinso/domain/recommend/entity/Recommend.java +++ b/src/main/java/com/tikitaka/naechinso/domain/recommend/entity/Recommend.java @@ -7,8 +7,10 @@ import com.tikitaka.naechinso.domain.recommend.dto.RecommendMemberAcceptRequestDTO; import com.tikitaka.naechinso.global.config.entity.BaseEntity; import lombok.*; +import org.apache.commons.lang3.StringUtils; import javax.persistence.*; +import java.util.List; import java.util.UUID; /** @@ -93,11 +95,8 @@ public class Recommend extends BaseEntity { @Column(name = "rec_meet") private String receiverMeet; - @Column(name = "rec_personality") - private String receiverPersonality; - - @Column(name = "rec_appeal") - private String receiverAppeal; + @Column(name = "rec_appeals") + private String receiverAppeals; @Column(name = "rec_appeal_detail") private String receiverAppealDetail; @@ -107,10 +106,16 @@ public class Recommend extends BaseEntity { public void update(RecommendAcceptRequestDTO requestDTO) { - this.receiverAppeal = requestDTO.getAppeal(); + this.receiverAppeals = StringUtils.join(requestDTO.getAppeals(), ","); this.receiverAppealDetail = requestDTO.getAppealDetail(); this.receiverMeet = requestDTO.getMeet(); - this.receiverPersonality = requestDTO.getPersonality(); this.receiverPeriod = requestDTO.getPeriod(); } + + public List getReceiverAppeals() { + if (this.receiverAppeals != null) { + return List.of(this.receiverAppeals.split(",")); + } + return List.of(); + } } From 6bc72c1b90b5559f12291e9b7851661cf4c43696 Mon Sep 17 00:00:00 2001 From: gengminy Date: Fri, 4 Nov 2022 15:01:09 +0900 Subject: [PATCH 57/72] =?UTF-8?q?:hammer:=20fix(prod):=20=ED=8C=8C?= =?UTF-8?q?=EC=9D=BC=20=EC=B5=9C=EB=8C=80=20=EC=9A=A9=EB=9F=89=20=EC=84=A4?= =?UTF-8?q?=EC=A0=95=20=EB=B3=80=EA=B2=BD=20#57?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .platform/nginx/nginx.conf | 2 +- src/main/resources/application.yml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.platform/nginx/nginx.conf b/.platform/nginx/nginx.conf index 5e4d910..629cb46 100644 --- a/.platform/nginx/nginx.conf +++ b/.platform/nginx/nginx.conf @@ -14,7 +14,7 @@ http { include /etc/nginx/mime.types; default_type application/octet-stream; - client_max_body_size 4M; + client_max_body_size 10M; log_format main '$remote_addr - $remote_user [$time_local] "$request" ' '$status $body_bytes_sent "$http_referer" ' diff --git a/src/main/resources/application.yml b/src/main/resources/application.yml index 612008e..282c9ab 100644 --- a/src/main/resources/application.yml +++ b/src/main/resources/application.yml @@ -5,7 +5,7 @@ spring: servlet: multipart: #file upload size - max-file-size: 3MB + max-file-size: 10MB profiles: active: local From 5d0b06cf227badc1b426de5637b197b4fad90bf8 Mon Sep 17 00:00:00 2001 From: gengminy Date: Sat, 5 Nov 2022 13:24:21 +0900 Subject: [PATCH 58/72] =?UTF-8?q?:hammer:=20fix(card):=20=EC=B6=94?= =?UTF-8?q?=EC=B2=9C=20=EC=B9=B4=EB=93=9C=20=EC=9D=91=EB=8B=B5=EC=97=90=20?= =?UTF-8?q?=EC=83=81=EB=8C=80=20id=20=EC=B6=94=EA=B0=80=20#41?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../domain/card/dto/CardOppositeMemberProfileResponseDTO.java | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/main/java/com/tikitaka/naechinso/domain/card/dto/CardOppositeMemberProfileResponseDTO.java b/src/main/java/com/tikitaka/naechinso/domain/card/dto/CardOppositeMemberProfileResponseDTO.java index e6ada8e..e688ee5 100644 --- a/src/main/java/com/tikitaka/naechinso/domain/card/dto/CardOppositeMemberProfileResponseDTO.java +++ b/src/main/java/com/tikitaka/naechinso/domain/card/dto/CardOppositeMemberProfileResponseDTO.java @@ -18,6 +18,8 @@ @ToString public class CardOppositeMemberProfileResponseDTO { + private Long targetMemberId; + private List images; private String name; private int age; @@ -102,6 +104,7 @@ public static CardOppositeMemberProfileResponseDTO of(Member member) { //추천 상태 검증 if (recommend.getSender() != null && recommend.getReceiver() != null) { return CardOppositeMemberProfileResponseDTO.builder() + .targetMemberId(member.getId()) .images(detail.getImages()) .name(CustomStringUtil.hideName(member.getName())) .age(member.getAge()) From 18ab671c69af2bd057efe5e2db47bcd18a3b6ae0 Mon Sep 17 00:00:00 2001 From: gengminy Date: Sat, 5 Nov 2022 14:44:11 +0900 Subject: [PATCH 59/72] =?UTF-8?q?:hammer:=20fix(member):=20=ED=86=A0?= =?UTF-8?q?=ED=81=B0=20=EC=9E=AC=EB=B0=9C=EA=B8=89=20=EC=9D=91=EB=8B=B5=20?= =?UTF-8?q?=EA=B0=92=20=EB=B3=80=EA=B2=BD=20#65?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../naechinso/domain/TestController.java | 51 +++++++++++-------- .../domain/member/MemberController.java | 2 +- .../domain/member/MemberService.java | 38 +++++++++++++- .../member/dto/MemberReissueResponseDTO.java | 29 +++++++++++ 4 files changed, 95 insertions(+), 25 deletions(-) create mode 100644 src/main/java/com/tikitaka/naechinso/domain/member/dto/MemberReissueResponseDTO.java diff --git a/src/main/java/com/tikitaka/naechinso/domain/TestController.java b/src/main/java/com/tikitaka/naechinso/domain/TestController.java index 0227aff..4122191 100644 --- a/src/main/java/com/tikitaka/naechinso/domain/TestController.java +++ b/src/main/java/com/tikitaka/naechinso/domain/TestController.java @@ -86,30 +86,37 @@ public CommonApiResponse generateRecommendRequestUser( @ApiOperation(value = "[*TEST*] 추천사를 받은 멤버를 임시 유저로 가입시킨 후 엑세스 토큰을 반환한다") public CommonApiResponse generateRecommendReceiver( ) { - - //sender - MemberCommonJoinResponseDTO senderDTO = memberService.joinCommonMember( - "01011112222", + List senderMemberInfo = Arrays.asList("01010101010", 25, Gender.M, "노경닉", "edu-image-admin.jpg", "홍익", "대학교", "컴퓨터공학과", "1~3년", "CMC에서 만남", "착함", "자기관리, 귀여워, 차분해", "자기 일을 진짜 책임감 있게 잘하고 주변을 늘 먼저 생각하는 친구야", "서울시 마포구", "1병", 180, "내친소 사용하기", "profile-001-01.png,profile-001-02.png,profile-001-03.png", "반갑습니다 내친소 여러분!", "ESTJ", "열정적인, 상냥한, 섬세한", "무교", "비흡연자", "같이 취미를 즐길 수 있는 연애를 하고 싶어"); //추천인 + Member sender = memberService.findByPhone(memberService.joinCommonMember( + (String) senderMemberInfo.get(0), MemberCommonJoinRequestDTO.builder() - .age(25) - .gender(Gender.M) - .name("닉") + .age((int) senderMemberInfo.get(1)) + .gender((Gender) senderMemberInfo.get(2)) + .name((String) senderMemberInfo.get(3)) .acceptsInfo(true) .acceptsLocation(true) .acceptsMarketing(true) .acceptsReligion(true) .acceptsService(true) - .build()); + .build()).getPhone()); + sender.updateEdu(MemberUpdateEduRequestDTO.builder() + .eduImage((String) senderMemberInfo.get(4)) + .eduName((String) senderMemberInfo.get(5)) + .eduLevel((String) senderMemberInfo.get(6)) + .eduMajor((String) senderMemberInfo.get(7)) + .build()); + memberRepository.save(sender); + memberRepository.flush(); - Member sender = memberService.findByPhone(senderDTO.getPhone()); - //sender + List receiverInfo = Arrays.asList("01012345678", 25, Gender.W, "진하수", "edu-image020.jpg", "연세", "대학교", "기계공학과", "1~3년", "CMC에서 만남", "착함", "패션센스 \uD83E\uDDE5,사랑꾼 \uD83D\uDC97,애교쟁이 \uD83D\uDE18", "자기 일을 진짜 책임감 있게 잘하고 주변을 늘 먼저 생각하는 친구야", "서울시 마포구", "1병", 163, "내친소 사용하기", "profile-001-01.png,profile-001-02.png,profile-001-03.png", "반갑습니다 내친소 여러분!", "ESTJ", "열정적인 \uD83D\uDD25,지적인 \uD83E\uDDD0,상냥한 ☺️", "무교", "비흡연자", "같이 취미를 즐길 수 있는 연애를 하고 싶어"); + //receiver MemberCommonJoinResponseDTO receiverDTO = memberService.joinCommonMember( - "01012345678", + (String) receiverInfo.get(0), MemberCommonJoinRequestDTO.builder() - .age(25) - .gender(Gender.M) - .name("닉") + .age((int) receiverInfo.get(1)) + .gender((Gender) receiverInfo.get(2)) + .name((String) receiverInfo.get(3)) .acceptsInfo(true) .acceptsLocation(true) .acceptsMarketing(true) @@ -119,16 +126,16 @@ public CommonApiResponse generateRecommendReceiver( RecommendResponseDTO recommend = recommendService.createRecommend(sender, RecommendBySenderRequestDTO .builder() - .age(25) - .period("1년") - .appeals(List.of("[패션센스 \uD83E\uDDE5", "사랑꾼 \uD83D\uDC97", "애교쟁이 \uD83D\uDE18")) - .phone("01012345678") - .meet("CMC에서") - .gender(Gender.M) - .name("닉") + .phone((String) receiverInfo.get(0)) + .age((int) receiverInfo.get(1)) + .gender((Gender) receiverInfo.get(2)) + .name((String) receiverInfo.get(3)) + .period((String) receiverInfo.get(8)) + .meet((String) receiverInfo.get(9)) + .appeals(List.of(StringUtils.split((String) receiverInfo.get(11), ","))) + .appealDetail((String) receiverInfo.get(12)) .build()); - return CommonApiResponse.of(receiverDTO); } diff --git a/src/main/java/com/tikitaka/naechinso/domain/member/MemberController.java b/src/main/java/com/tikitaka/naechinso/domain/member/MemberController.java index ad8e5ee..6a0cfb6 100644 --- a/src/main/java/com/tikitaka/naechinso/domain/member/MemberController.java +++ b/src/main/java/com/tikitaka/naechinso/domain/member/MemberController.java @@ -84,7 +84,7 @@ public CommonApiResponse forceLogin( @PostMapping("/reissue") @ApiOperation(value = "리프레시 토큰을 통해 새로운 토큰을 발급받는다 (RefreshToken)") - public CommonApiResponse reissue( + public CommonApiResponse reissue( @RequestHeader("Authorization") String accessToken, @RequestHeader("Refresh") String refreshToken ) { diff --git a/src/main/java/com/tikitaka/naechinso/domain/member/MemberService.java b/src/main/java/com/tikitaka/naechinso/domain/member/MemberService.java index 25827a5..4baf7d4 100644 --- a/src/main/java/com/tikitaka/naechinso/domain/member/MemberService.java +++ b/src/main/java/com/tikitaka/naechinso/domain/member/MemberService.java @@ -10,6 +10,8 @@ import com.tikitaka.naechinso.domain.pending.constant.PendingType; import com.tikitaka.naechinso.domain.pending.dto.PendingFindResponseDTO; import com.tikitaka.naechinso.domain.pending.dto.PendingUpdateMemberImageRequestDTO; +import com.tikitaka.naechinso.domain.recommend.RecommendRepository; +import com.tikitaka.naechinso.domain.recommend.dto.RecommendReceiverDTO; import com.tikitaka.naechinso.domain.recommend.entity.Recommend; import com.tikitaka.naechinso.global.common.request.TokenRequestDTO; import com.tikitaka.naechinso.global.common.response.TokenResponseDTO; @@ -34,6 +36,7 @@ public class MemberService { private final JwtTokenProvider jwtTokenProvider; private final PendingService pendingService; + private final RecommendRepository recommendRepository; private final MemberRepository memberRepository; private final MemberDetailRepository memberDetailRepository; @@ -91,7 +94,7 @@ public MemberLoginResponseDTO logout(Member authMember) { * 로그인 -> Fcm Token DB에 등록한다 * @// TODO: 2022/10/30 노션에 정리 * */ - public TokenResponseDTO reissue(String accessToken, String refreshToken) { + public MemberReissueResponseDTO reissue(String accessToken, String refreshToken) { String phone; if (!jwtTokenProvider.validateTokenExceptExpiration(accessToken)){ @@ -105,8 +108,34 @@ public TokenResponseDTO reissue(String accessToken, String refreshToken) { } Member authMember = findByPhone(phone); + + //가입 여부 (detail == null) 확인 후 받은 추천서 꺼내옴 + final Boolean hasDetail = authMember.getDetail() != null; + + //만약 정회원이 아니라면 받은 추천 목록을 가져옴 + List recommendReceived; + if (!hasDetail) { + recommendReceived = recommendRepository.findAllByReceiverPhoneAndSenderNotNull(phone) + .stream().map(RecommendReceiverDTO::of).collect(Collectors.toList()); + } else { + recommendReceived = null; + } + + //유저 밴 여부 가져오기 + final Boolean isBanned = false; + jwtTokenProvider.validateRefreshToken(phone, refreshToken); - return jwtTokenProvider.generateToken(new JwtDTO(phone, authMember.getRole().toString())); + + TokenResponseDTO tokenResponseDTO = jwtTokenProvider.generateToken(new JwtDTO(phone, authMember.getRole().toString())); + + + return MemberReissueResponseDTO.builder() + .accessToken(tokenResponseDTO.getAccessToken()) + .refreshToken(tokenResponseDTO.getRefreshToken()) + .recommendReceived(recommendReceived) + .isActive(hasDetail) + .isBanned(isBanned) + .build(); } @@ -145,6 +174,11 @@ public MemberDetailResponseDTO readDetail(Member member) { return MemberDetailResponseDTO.of(member); } + + /** + * 추천사를 받은 유저의 세부 회원 가입 + * @// TODO: 2022/11/05 기본 정보도 추가로 수정 + **/ public MemberDetailResponseDTO createDetail(Member authMember, MemberDetailJoinRequestDTO dto) { //영속성 유지를 위한 fetch Member member = findByMember(authMember); diff --git a/src/main/java/com/tikitaka/naechinso/domain/member/dto/MemberReissueResponseDTO.java b/src/main/java/com/tikitaka/naechinso/domain/member/dto/MemberReissueResponseDTO.java new file mode 100644 index 0000000..32044ba --- /dev/null +++ b/src/main/java/com/tikitaka/naechinso/domain/member/dto/MemberReissueResponseDTO.java @@ -0,0 +1,29 @@ +package com.tikitaka.naechinso.domain.member.dto; + +import com.fasterxml.jackson.annotation.JsonInclude; +import com.tikitaka.naechinso.domain.recommend.dto.RecommendReceiverDTO; +import lombok.*; + +import java.util.ArrayList; +import java.util.List; + +/** + * 토큰 재발급을 담당하는 응답 DTO + * */ +@AllArgsConstructor +@NoArgsConstructor +@Getter +@Builder +@ToString +@JsonInclude(JsonInclude.Include.NON_NULL) //NULL 필드 가림 +public class MemberReissueResponseDTO { + private String accessToken; + private String refreshToken; + + //내 번호로 추천받은 정보 리스트 + private List recommendReceived; + //가입 완료했는지 여부, detail 정보가 있으면 true + private Boolean isActive = false; + //서버로부터 차단 당했는지 여부 + private Boolean isBanned = false; +} From ec08e24c78239a6d3a483efb8c14e549cf6eb86d Mon Sep 17 00:00:00 2001 From: gengminy Date: Sat, 5 Nov 2022 14:52:31 +0900 Subject: [PATCH 60/72] =?UTF-8?q?:hammer:=20fix(member):=20=EC=A0=95?= =?UTF-8?q?=ED=9A=8C=EC=9B=90=20=EA=B0=80=EC=9E=85=20=EC=8B=9C=20=EA=B8=B0?= =?UTF-8?q?=EB=B3=B8=EC=A0=95=EB=B3=B4=20=EC=97=85=EB=8D=B0=EC=9D=B4?= =?UTF-8?q?=ED=8A=B8=20#66?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../naechinso/domain/member/MemberService.java | 4 +++- .../domain/member/dto/MemberDetailJoinRequestDTO.java | 4 ---- .../naechinso/domain/member/entity/Member.java | 11 +++++++---- 3 files changed, 10 insertions(+), 9 deletions(-) diff --git a/src/main/java/com/tikitaka/naechinso/domain/member/MemberService.java b/src/main/java/com/tikitaka/naechinso/domain/member/MemberService.java index 4baf7d4..291cc43 100644 --- a/src/main/java/com/tikitaka/naechinso/domain/member/MemberService.java +++ b/src/main/java/com/tikitaka/naechinso/domain/member/MemberService.java @@ -128,7 +128,6 @@ public MemberReissueResponseDTO reissue(String accessToken, String refreshToken) TokenResponseDTO tokenResponseDTO = jwtTokenProvider.generateToken(new JwtDTO(phone, authMember.getRole().toString())); - return MemberReissueResponseDTO.builder() .accessToken(tokenResponseDTO.getAccessToken()) .refreshToken(tokenResponseDTO.getRefreshToken()) @@ -201,6 +200,9 @@ public MemberDetailResponseDTO createDetail(Member authMember, MemberDetailJoinR //받은 추천사 중 한명이라도 인증이 완료된 상태면 정회원 가입 실행 if (recommend.getSender().getJobAccepted() || recommend.getSender().getEduAccepted()) { + member.updateCommonInfo(dto); + memberRepository.save(member); + MemberDetail detail = MemberDetail.of(member, dto); memberDetailRepository.save(detail); diff --git a/src/main/java/com/tikitaka/naechinso/domain/member/dto/MemberDetailJoinRequestDTO.java b/src/main/java/com/tikitaka/naechinso/domain/member/dto/MemberDetailJoinRequestDTO.java index bfb0f76..1c54873 100644 --- a/src/main/java/com/tikitaka/naechinso/domain/member/dto/MemberDetailJoinRequestDTO.java +++ b/src/main/java/com/tikitaka/naechinso/domain/member/dto/MemberDetailJoinRequestDTO.java @@ -57,10 +57,6 @@ public class MemberDetailJoinRequestDTO { @Length(max = 4, message = "올바른 MBTI 정보를 입력하세요") private String mbti; -// @ApiModelProperty(example = "직관적") -// @NotBlank(message = "성격 정보를 입력해야 합니다") -// private String personality; - @ApiModelProperty(example = "[\"열정적인 \uD83D\uDD25\", \"지적인 \uD83E\uDDD0\", \"상냥한 ☺️\"]") @Size(min = 3, max = 3, message = "성격 키워드 3개를 입력해야 합니다") @NotNull diff --git a/src/main/java/com/tikitaka/naechinso/domain/member/entity/Member.java b/src/main/java/com/tikitaka/naechinso/domain/member/entity/Member.java index 4bfa017..c48cb64 100644 --- a/src/main/java/com/tikitaka/naechinso/domain/member/entity/Member.java +++ b/src/main/java/com/tikitaka/naechinso/domain/member/entity/Member.java @@ -5,10 +5,7 @@ import com.tikitaka.naechinso.domain.match.entity.Match; import com.tikitaka.naechinso.domain.member.constant.Gender; import com.tikitaka.naechinso.domain.member.constant.Role; -import com.tikitaka.naechinso.domain.member.dto.MemberUpdateAcceptsRequestDTO; -import com.tikitaka.naechinso.domain.member.dto.MemberUpdateCommonRequestDTO; -import com.tikitaka.naechinso.domain.member.dto.MemberUpdateEduRequestDTO; -import com.tikitaka.naechinso.domain.member.dto.MemberUpdateJobRequestDTO; +import com.tikitaka.naechinso.domain.member.dto.*; import com.tikitaka.naechinso.domain.pending.entity.Pending; import com.tikitaka.naechinso.domain.point.constant.PointType; import com.tikitaka.naechinso.domain.point.entity.Point; @@ -202,6 +199,12 @@ public void setDetail(MemberDetail memberDetail) { this.detail = memberDetail; } + public void updateCommonInfo(MemberDetailJoinRequestDTO requestDTO) { + this.name = requestDTO.getName(); + this.age = requestDTO.getAge(); + this.gender = requestDTO.getGender(); + } + public void updateAccepts(MemberUpdateAcceptsRequestDTO requestDTO) { this.acceptsMarketing = requestDTO.isAcceptsMarketing(); this.acceptsPush = requestDTO.isAcceptsPush(); From d801d279613dbc4c3783dea23c0f8d0bc209b930 Mon Sep 17 00:00:00 2001 From: gengminy Date: Sat, 5 Nov 2022 15:05:14 +0900 Subject: [PATCH 61/72] =?UTF-8?q?:hammer:=20fix(member):=20=EB=82=98?= =?UTF-8?q?=EC=9D=B4=20=EC=A0=95=EB=B3=B4=20=EC=97=B0=EB=8F=84=EB=A1=9C=20?= =?UTF-8?q?=EC=88=98=EC=A0=95=20#39?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../naechinso/domain/TestController.java | 66 +++++++++---------- .../dto/MemberCommonJoinRequestDTO.java | 6 +- .../dto/MemberDetailJoinRequestDTO.java | 6 +- .../dto/MemberUpdateCommonRequestDTO.java | 6 +- 4 files changed, 42 insertions(+), 42 deletions(-) diff --git a/src/main/java/com/tikitaka/naechinso/domain/TestController.java b/src/main/java/com/tikitaka/naechinso/domain/TestController.java index 4122191..f908558 100644 --- a/src/main/java/com/tikitaka/naechinso/domain/TestController.java +++ b/src/main/java/com/tikitaka/naechinso/domain/TestController.java @@ -66,7 +66,7 @@ public CommonApiResponse generateRecommendRequestUser( MemberCommonJoinResponseDTO responseDTO = memberService.joinCommonMember( "01012345678", MemberCommonJoinRequestDTO.builder() - .age(25) + .age(1998) .gender(Gender.M) .name("닉") .acceptsInfo(true) @@ -86,7 +86,7 @@ public CommonApiResponse generateRecommendRequestUser( @ApiOperation(value = "[*TEST*] 추천사를 받은 멤버를 임시 유저로 가입시킨 후 엑세스 토큰을 반환한다") public CommonApiResponse generateRecommendReceiver( ) { - List senderMemberInfo = Arrays.asList("01010101010", 25, Gender.M, "노경닉", "edu-image-admin.jpg", "홍익", "대학교", "컴퓨터공학과", "1~3년", "CMC에서 만남", "착함", "자기관리, 귀여워, 차분해", "자기 일을 진짜 책임감 있게 잘하고 주변을 늘 먼저 생각하는 친구야", "서울시 마포구", "1병", 180, "내친소 사용하기", "profile-001-01.png,profile-001-02.png,profile-001-03.png", "반갑습니다 내친소 여러분!", "ESTJ", "열정적인, 상냥한, 섬세한", "무교", "비흡연자", "같이 취미를 즐길 수 있는 연애를 하고 싶어"); //추천인 + List senderMemberInfo = Arrays.asList("01010101010", 1998, Gender.M, "노경닉", "edu-image-admin.jpg", "홍익", "대학교", "컴퓨터공학과", "1~3년", "CMC에서 만남", "착함", "자기관리, 귀여워, 차분해", "자기 일을 진짜 책임감 있게 잘하고 주변을 늘 먼저 생각하는 친구야", "서울시 마포구", "1병", 180, "내친소 사용하기", "profile-001-01.png,profile-001-02.png,profile-001-03.png", "반갑습니다 내친소 여러분!", "ESTJ", "열정적인, 상냥한, 섬세한", "무교", "비흡연자", "같이 취미를 즐길 수 있는 연애를 하고 싶어"); //추천인 Member sender = memberService.findByPhone(memberService.joinCommonMember( (String) senderMemberInfo.get(0), MemberCommonJoinRequestDTO.builder() @@ -109,7 +109,7 @@ public CommonApiResponse generateRecommendReceiver( memberRepository.flush(); - List receiverInfo = Arrays.asList("01012345678", 25, Gender.W, "진하수", "edu-image020.jpg", "연세", "대학교", "기계공학과", "1~3년", "CMC에서 만남", "착함", "패션센스 \uD83E\uDDE5,사랑꾼 \uD83D\uDC97,애교쟁이 \uD83D\uDE18", "자기 일을 진짜 책임감 있게 잘하고 주변을 늘 먼저 생각하는 친구야", "서울시 마포구", "1병", 163, "내친소 사용하기", "profile-001-01.png,profile-001-02.png,profile-001-03.png", "반갑습니다 내친소 여러분!", "ESTJ", "열정적인 \uD83D\uDD25,지적인 \uD83E\uDDD0,상냥한 ☺️", "무교", "비흡연자", "같이 취미를 즐길 수 있는 연애를 하고 싶어"); + List receiverInfo = Arrays.asList("01012345678", 1998, Gender.W, "진하수", "edu-image020.jpg", "연세", "대학교", "기계공학과", "1~3년", "CMC에서 만남", "착함", "패션센스 \uD83E\uDDE5,사랑꾼 \uD83D\uDC97,애교쟁이 \uD83D\uDE18", "자기 일을 진짜 책임감 있게 잘하고 주변을 늘 먼저 생각하는 친구야", "서울시 마포구", "1병", 163, "내친소 사용하기", "profile-001-01.png,profile-001-02.png,profile-001-03.png", "반갑습니다 내친소 여러분!", "ESTJ", "열정적인 \uD83D\uDD25,지적인 \uD83E\uDDD0,상냥한 ☺️", "무교", "비흡연자", "같이 취미를 즐길 수 있는 연애를 하고 싶어"); //receiver MemberCommonJoinResponseDTO receiverDTO = memberService.joinCommonMember( (String) receiverInfo.get(0), @@ -147,7 +147,7 @@ public CommonApiResponse createJobPendingMember( MemberCommonJoinResponseDTO responseDTO = memberService.joinCommonMember( "01012345678", MemberCommonJoinRequestDTO.builder() - .age(25) + .age(1998) .gender(Gender.M) .name("닉") .acceptsInfo(true) @@ -189,7 +189,7 @@ public CommonApiResponse createJobPendingMemberAndRecommendOther( MemberCommonJoinResponseDTO senderDTO = memberService.joinCommonMember( "01012345678", MemberCommonJoinRequestDTO.builder() - .age(25) + .age(1998) .gender(Gender.M) .name("닉") .acceptsInfo(true) @@ -206,7 +206,7 @@ public CommonApiResponse createJobPendingMemberAndRecommendOther( MemberCommonJoinResponseDTO receiverDTO = memberService.joinCommonMember( "01011111111", MemberCommonJoinRequestDTO.builder() - .age(25) + .age(1998) .gender(Gender.M) .name("닉") .acceptsInfo(true) @@ -219,7 +219,7 @@ public CommonApiResponse createJobPendingMemberAndRecommendOther( System.out.println("recommend = " + recommendService.createRecommend(member1, RecommendBySenderRequestDTO .builder() - .age(25) + .age(1998) .period("1년") .appeals(List.of("[패션센스 \uD83E\uDDE5", "사랑꾼 \uD83D\uDC97", "애교쟁이 \uD83D\uDE18")) .phone("01011111111") @@ -251,7 +251,7 @@ public CommonApiResponse createTwoRegularMember() { MemberCommonJoinResponseDTO senderDTO = memberService.joinCommonMember( "01012345678", MemberCommonJoinRequestDTO.builder() - .age(25) + .age(1998) .gender(Gender.W) .name("아이유") .acceptsInfo(true) @@ -272,7 +272,7 @@ public CommonApiResponse createTwoRegularMember() { MemberCommonJoinResponseDTO receiverDTO = memberService.joinCommonMember( "01011111111", MemberCommonJoinRequestDTO.builder() - .age(28) + .age(1995) .gender(Gender.M) .name("지드래곤") .acceptsInfo(true) @@ -292,7 +292,7 @@ public CommonApiResponse createTwoRegularMember() { recommendService.createRecommend(member2, RecommendBySenderRequestDTO .builder() - .age(25) + .age(1998) .period("3달") .appeals(List.of("[패션센스 \uD83E\uDDE5", "사랑꾼 \uD83D\uDC97", "애교쟁이 \uD83D\uDE18")) .appealDetail("짱짱짱 멋짐") @@ -305,7 +305,7 @@ public CommonApiResponse createTwoRegularMember() { recommendService.createRecommend(member1, RecommendBySenderRequestDTO .builder() - .age(25) + .age(1998) .period("1년") .appeals(List.of("[패션센스 \uD83E\uDDE5", "사랑꾼 \uD83D\uDC97", "애교쟁이 \uD83D\uDE18")) .appealDetail("짱짱짱 멋짐") @@ -358,7 +358,7 @@ public CommonApiResponse createTwoRegularMember() { @GetMapping("/create-multiple-users") @ApiOperation(value = "[*TEST*] 정회원으로 가입한 유저를 남녀 10명씩 생성하고, 그 중 마지막 여성 멤버 하나의 엑세스 토큰 반환") public CommonApiResponse createMultipleMembers() { - List adminMemberInfo = Arrays.asList("01012345678", 25, Gender.M, "노경닉", "edu-image-admin.jpg", "홍익", "대학교", "컴퓨터공학과", "1~3년", "CMC에서 만남", "착함", "패션센스 \uD83E\uDDE5,사랑꾼 \uD83D\uDC97,애교쟁이 \uD83D\uDE18", "자기 일을 진짜 책임감 있게 잘하고 주변을 늘 먼저 생각하는 친구야", "서울시 마포구", "1병", 180, "내친소 사용하기", "profile-001-01.png,profile-001-02.png,profile-001-03.png", "반갑습니다 내친소 여러분!", "ESTJ", "열정적인 \uD83D\uDD25,지적인 \uD83E\uDDD0,상냥한 ☺️", "무교", "비흡연자", "같이 취미를 즐길 수 있는 연애를 하고 싶어"); //어드민 겸 추천인 + List adminMemberInfo = Arrays.asList("01012345678", 1998, Gender.M, "노경닉", "edu-image-admin.jpg", "홍익", "대학교", "컴퓨터공학과", "1~3년", "CMC에서 만남", "착함", "패션센스 \uD83E\uDDE5,사랑꾼 \uD83D\uDC97,애교쟁이 \uD83D\uDE18", "자기 일을 진짜 책임감 있게 잘하고 주변을 늘 먼저 생각하는 친구야", "서울시 마포구", "1병", 180, "내친소 사용하기", "profile-001-01.png,profile-001-02.png,profile-001-03.png", "반갑습니다 내친소 여러분!", "ESTJ", "열정적인 \uD83D\uDD25,지적인 \uD83E\uDDD0,상냥한 ☺️", "무교", "비흡연자", "같이 취미를 즐길 수 있는 연애를 하고 싶어"); //어드민 겸 추천인 Member adminMember = memberService.findByPhone(memberService.joinCommonMember( (String) adminMemberInfo.get(0), @@ -382,27 +382,27 @@ public CommonApiResponse createMultipleMembers() { memberRepository.save(adminMember); final List> joinRequestList = Arrays.asList( - Arrays.asList("01011111111", 25, Gender.M, "허시준", "edu-image001.jpg", "서강", "대학교", "컴퓨터공학과", "1~3년", "CMC에서 만남", "착함", "\"패션센스 \uD83E\uDDE5\", \"사랑꾼 \uD83D\uDC97\", \"애교쟁이 \uD83D\uDE18\"", "자기 일을 진짜 책임감 있게 잘하고 주변을 늘 먼저 생각하는 친구야", "서울시 마포구", "1병", 180, "내친소 사용하기", "profile-001-01.png,profile-001-02.png,profile-001-03.png", "반갑습니다 내친소 여러분!", "ESTJ", "열정적인 \uD83D\uDD25,지적인 \uD83E\uDDD0,상냥한 ☺️", "무교", "비흡연자", "같이 취미를 즐길 수 있는 연애를 하고 싶어"), - Arrays.asList("01012222222", 26, Gender.M, "민성진", "edu-image002.jpg", "한국", "고등학교", "자동차정비", "1~3년", "CMC에서 만남", "착함", "패션센스 \uD83E\uDDE5,사랑꾼 \uD83D\uDC97,애교쟁이 \uD83D\uDE18", "자기 일을 진짜 책임감 있게 잘하고 주변을 늘 먼저 생각하는 친구야", "서울시 마포구", "1병", 185, "내친소 사용하기", "profile-001-01.png,profile-001-02.png,profile-001-03.png", "반갑습니다 내친소 여러분!", "INFP", "열정적인 \uD83D\uDD25,지적인 \uD83E\uDDD0,상냥한 ☺️", "무교", "비흡연자", "같이 취미를 즐길 수 있는 연애를 하고 싶어"), - Arrays.asList("01013333333", 27, Gender.M, "김상혁", "edu-image003.jpg", "서울", "대학원", "인공지능공학", "1~3년", "CMC에서 만남", "착함", "패션센스 \uD83E\uDDE5,사랑꾼 \uD83D\uDC97,애교쟁이 \uD83D\uDE18", "자기 일을 진짜 책임감 있게 잘하고 주변을 늘 먼저 생각하는 친구야", "서울시 마포구", "1병", 182, "내친소 사용하기", "profile-001-01.png,profile-001-02.png,profile-001-03.png", "반갑습니다 내친소 여러분!", "ESTJ", "열정적인 \uD83D\uDD25,지적인 \uD83E\uDDD0,상냥한 ☺️", "기독교", "비흡연자", "같이 취미를 즐길 수 있는 연애를 하고 싶어"), - Arrays.asList("01014444444", 28, Gender.M, "권영성", "edu-image004.jpg", "홍익", "대학교", "시각디자인학과", "1~3년", "CMC에서 만남", "착함", "패션센스 \uD83E\uDDE5,사랑꾼 \uD83D\uDC97,애교쟁이 \uD83D\uDE18", "자기 일을 진짜 책임감 있게 잘하고 주변을 늘 먼저 생각하는 친구야", "서울시 마포구", "1병", 183, "내친소 사용하기", "profile-001-01.png,profile-001-02.png,profile-001-03.png", "반갑습니다 내친소 여러분!", "INFJ", "열정적인 \uD83D\uDD25,지적인 \uD83E\uDDD0,상냥한 ☺️", "불교", "비흡연자", "같이 취미를 즐길 수 있는 연애를 하고 싶어"), - Arrays.asList("01015555555", 29, Gender.M, "배규빈", "edu-image005.jpg", "한성", "고등학교", "상업", "3~5년", "CMC에서 만남", "착함", "패션센스 \uD83E\uDDE5,사랑꾼 \uD83D\uDC97,애교쟁이 \uD83D\uDE18", "자기 일을 진짜 책임감 있게 잘하고 주변을 늘 먼저 생각하는 친구야", "서울시 마포구", "1병", 178, "내친소 사용하기", "profile-001-01.png,profile-001-02.png,profile-001-03.png", "반갑습니다 내친소 여러분!", "ESTJ", "열정적인 \uD83D\uDD25,지적인 \uD83E\uDDD0,상냥한 ☺️", "무교", "비흡연자", "같이 취미를 즐길 수 있는 연애를 하고 싶어"), - Arrays.asList("01016666666", 30, Gender.M, "권민기", "edu-image006.jpg", "서울", "고등학교", "디자인", "3~5년", "CMC에서 만남", "착함", "패션센스 \uD83E\uDDE5,사랑꾼 \uD83D\uDC97,애교쟁이 \uD83D\uDE18", "자기 일을 진짜 책임감 있게 잘하고 주변을 늘 먼저 생각하는 친구야", "서울시 마포구", "1병", 172, "내친소 사용하기", "profile-001-01.png,profile-001-02.png,profile-001-03.png", "반갑습니다 내친소 여러분!", "ESFJ", "열정적인 \uD83D\uDD25,지적인 \uD83E\uDDD0,상냥한 ☺️", "무교", "비흡연자", "같이 취미를 즐길 수 있는 연애를 하고 싶어"), - Arrays.asList("01017777777", 31, Gender.M, "김민성", "edu-image007.jpg", "연세", "대학원", "영어영문학과", "1~3년", "CMC에서 만남", "착함", "패션센스 \uD83E\uDDE5,사랑꾼 \uD83D\uDC97,애교쟁이 \uD83D\uDE18", "자기 일을 진짜 책임감 있게 잘하고 주변을 늘 먼저 생각하는 친구야", "서울시 마포구", "1병", 173, "내친소 사용하기", "profile-001-01.png,profile-001-02.png,profile-001-03.png", "반갑습니다 내친소 여러분!", "ENFP", "열정적인 \uD83D\uDD25,지적인 \uD83E\uDDD0,상냥한 ☺️", "기독교", "비흡연자", "같이 취미를 즐길 수 있는 연애를 하고 싶어"), - Arrays.asList("01018888888", 32, Gender.M, "임정혁", "edu-image008.jpg", "연세", "대학교", "전기전자공학과", "1~3년", "CMC에서 만남", "착함", "패션센스 \uD83E\uDDE5,사랑꾼 \uD83D\uDC97,애교쟁이 \uD83D\uDE18", "자기 일을 진짜 책임감 있게 잘하고 주변을 늘 먼저 생각하는 친구야", "서울시 마포구", "1병", 175, "내친소 사용하기", "profile-001-01.png,profile-001-02.png,profile-001-03.png", "반갑습니다 내친소 여러분!", "ESTJ", "열정적인 \uD83D\uDD25,지적인 \uD83E\uDDD0,상냥한 ☺️", "무교", "비흡연자", "같이 취미를 즐길 수 있는 연애를 하고 싶어"), - Arrays.asList("01019999999", 33, Gender.M, "성재오", "edu-image009.jpg", "이대부속", "고등학교", "공학", "1~3년", "CMC에서 만남", "착함", "패션센스 \uD83E\uDDE5,사랑꾼 \uD83D\uDC97,애교쟁이 \uD83D\uDE18", "자기 일을 진짜 책임감 있게 잘하고 주변을 늘 먼저 생각하는 친구야", "서울시 마포구", "1병", 168, "내친소 사용하기", "profile-001-01.png,profile-001-02.png,profile-001-03.png", "반갑습니다 내친소 여러분!", "ESTJ", "열정적인 \uD83D\uDD25,지적인 \uD83E\uDDD0,상냥한 ☺️", "무교", "비흡연자", "같이 취미를 즐길 수 있는 연애를 하고 싶어"), - Arrays.asList("01010000000", 25, Gender.M, "차재훈", "edu-image010.jpg", "국민", "대학교", "미디어학과", "1~3년", "CMC에서 만남", "착함", "패션센스 \uD83E\uDDE5,사랑꾼 \uD83D\uDC97,애교쟁이 \uD83D\uDE18", "자기 일을 진짜 책임감 있게 잘하고 주변을 늘 먼저 생각하는 친구야", "서울시 마포구", "1병", 176, "내친소 사용하기", "profile-001-01.png,profile-001-02.png,profile-001-03.png", "반갑습니다 내친소 여러분!", "ESTP", "열정적인 \uD83D\uDD25,지적인 \uD83E\uDDD0,상냥한 ☺️", "무교", "비흡연자", "같이 취미를 즐길 수 있는 연애를 하고 싶어"), - - Arrays.asList("01022200000", 25, Gender.W, "민장효", "edu-image011.jpg", "서강", "대학원", "물류학과", "1~3년", "CMC에서 만남", "착함", "패션센스 \uD83E\uDDE5,사랑꾼 \uD83D\uDC97,애교쟁이 \uD83D\uDE18", "자기 일을 진짜 책임감 있게 잘하고 주변을 늘 먼저 생각하는 친구야", "서울시 마포구", "1병", 160, "내친소 사용하기", "profile-001-01.png,profile-001-02.png,profile-001-03.png", "반갑습니다 내친소 여러분!", "INFP", "열정적인 \uD83D\uDD25,지적인 \uD83E\uDDD0,상냥한 ☺️", "무교", "비흡연자", "같이 취미를 즐길 수 있는 연애를 하고 싶어"), - Arrays.asList("01022211111", 25, Gender.W, "김민서", "edu-image012.jpg", "홍익", "대학교", "조소과", "1~3년", "CMC에서 만남", "착함", "패션센스 \uD83E\uDDE5,사랑꾼 \uD83D\uDC97,애교쟁이 \uD83D\uDE18", "자기 일을 진짜 책임감 있게 잘하고 주변을 늘 먼저 생각하는 친구야", "서울시 마포구", "1병", 162, "내친소 사용하기", "profile-001-01.png,profile-001-02.png,profile-001-03.png", "반갑습니다 내친소 여러분!", "ESTJ", "열정적인 \uD83D\uDD25,지적인 \uD83E\uDDD0,상냥한 ☺️", "무교", "비흡연자", "같이 취미를 즐길 수 있는 연애를 하고 싶어"), - Arrays.asList("01022222222", 25, Gender.W, "노혜지", "edu-image013.jpg", "한국", "고등학교", "디자인", "1~3년", "CMC에서 만남", "착함", "패션센스 \uD83E\uDDE5,사랑꾼 \uD83D\uDC97,애교쟁이 \uD83D\uDE18", "자기 일을 진짜 책임감 있게 잘하고 주변을 늘 먼저 생각하는 친구야", "서울시 마포구", "1병", 165, "내친소 사용하기", "profile-001-01.png,profile-001-02.png,profile-001-03.png", "반갑습니다 내친소 여러분!", "ENFP", "열정적인 \uD83D\uDD25,지적인 \uD83E\uDDD0,상냥한 ☺️", "기독교", "비흡연자", "같이 취미를 즐길 수 있는 연애를 하고 싶어"), - Arrays.asList("01022233333", 25, Gender.W, "류라해", "edu-image014.jpg", "이화여자", "대학교", "사이버보안학과", "1~3년", "CMC에서 만남", "착함", "패션센스 \uD83E\uDDE5,사랑꾼 \uD83D\uDC97,애교쟁이 \uD83D\uDE18", "자기 일을 진짜 책임감 있게 잘하고 주변을 늘 먼저 생각하는 친구야", "서울시 마포구", "1병", 155, "내친소 사용하기", "profile-001-01.png,profile-001-02.png,profile-001-03.png", "반갑습니다 내친소 여러분!", "ESTJ", "열정적인 \uD83D\uDD25,지적인 \uD83E\uDDD0,상냥한 ☺️", "기독교", "비흡연자", "같이 취미를 즐길 수 있는 연애를 하고 싶어"), - Arrays.asList("01022244444", 25, Gender.W, "민예지", "edu-image015.jpg", "이화여자", "대학교", "국어국문학과", "3~5년", "CMC에서 만남", "착함", "패션센스 \uD83E\uDDE5,사랑꾼 \uD83D\uDC97,애교쟁이 \uD83D\uDE18", "자기 일을 진짜 책임감 있게 잘하고 주변을 늘 먼저 생각하는 친구야", "서울시 마포구", "1병", 150, "내친소 사용하기", "profile-001-01.png,profile-001-02.png,profile-001-03.png", "반갑습니다 내친소 여러분!", "INFJ", "열정적인 \uD83D\uDD25,지적인 \uD83E\uDDD0,상냥한 ☺️", "무교", "비흡연자", "같이 취미를 즐길 수 있는 연애를 하고 싶어"), - Arrays.asList("01022255555", 25, Gender.W, "류유주", "edu-image016.jpg", "한국", "고등학교", "공학", "1~3년", "CMC에서 만남", "착함", "패션센스 \uD83E\uDDE5,사랑꾼 \uD83D\uDC97,애교쟁이 \uD83D\uDE18", "자기 일을 진짜 책임감 있게 잘하고 주변을 늘 먼저 생각하는 친구야", "서울시 마포구", "1병", 174, "내친소 사용하기", "profile-001-01.png,profile-001-02.png,profile-001-03.png", "반갑습니다 내친소 여러분!", "INTP", "열정적인 \uD83D\uDD25,지적인 \uD83E\uDDD0,상냥한 ☺️", "기독교", "비흡연자", "같이 취미를 즐길 수 있는 연애를 하고 싶어"), - Arrays.asList("01022266666", 25, Gender.W, "임혜서", "edu-image017.jpg", "서울", "대학원", "법학과", "1~3년", "CMC에서 만남", "착함", "패션센스 \uD83E\uDDE5,사랑꾼 \uD83D\uDC97,애교쟁이 \uD83D\uDE18", "자기 일을 진짜 책임감 있게 잘하고 주변을 늘 먼저 생각하는 친구야", "서울시 마포구", "1병", 172, "내친소 사용하기", "profile-001-01.png,profile-001-02.png,profile-001-03.png", "반갑습니다 내친소 여러분!", "ESTJ", "열정적인 \uD83D\uDD25,지적인 \uD83E\uDDD0,상냥한 ☺️", "불교", "비흡연자", "같이 취미를 즐길 수 있는 연애를 하고 싶어"), - Arrays.asList("01022277777", 25, Gender.W, "임한하", "edu-image018.jpg", "서울", "대학교", "의상학과", "3~5년", "CMC에서 만남", "착함", "패션센스 \uD83E\uDDE5,사랑꾼 \uD83D\uDC97,애교쟁이 \uD83D\uDE18", "자기 일을 진짜 책임감 있게 잘하고 주변을 늘 먼저 생각하는 친구야", "서울시 마포구", "1병", 168, "내친소 사용하기", "profile-001-01.png,profile-001-02.png,profile-001-03.png", "반갑습니다 내친소 여러분!", "ENTP", "열정적인 \uD83D\uDD25,지적인 \uD83E\uDDD0,상냥한 ☺️", "무교", "비흡연자", "같이 취미를 즐길 수 있는 연애를 하고 싶어"), - Arrays.asList("01022288888", 25, Gender.W, "권민영", "edu-image019.jpg", "고려", "대학교", "의학", "1~3년", "CMC에서 만남", "착함", "패션센스 \uD83E\uDDE5,사랑꾼 \uD83D\uDC97,애교쟁이 \uD83D\uDE18", "자기 일을 진짜 책임감 있게 잘하고 주변을 늘 먼저 생각하는 친구야", "서울시 마포구", "1병", 175, "내친소 사용하기", "profile-001-01.png,profile-001-02.png,profile-001-03.png", "반갑습니다 내친소 여러분!", "ESFJ", "열정적인 \uD83D\uDD25,지적인 \uD83E\uDDD0,상냥한 ☺️", "무교", "비흡연자", "같이 취미를 즐길 수 있는 연애를 하고 싶어"), - Arrays.asList("01022299999", 25, Gender.W, "진하수", "edu-image020.jpg", "연세", "대학교", "기계공학과", "1~3년", "CMC에서 만남", "착함", "패션센스 \uD83E\uDDE5,사랑꾼 \uD83D\uDC97,애교쟁이 \uD83D\uDE18", "자기 일을 진짜 책임감 있게 잘하고 주변을 늘 먼저 생각하는 친구야", "서울시 마포구", "1병", 163, "내친소 사용하기", "profile-001-01.png,profile-001-02.png,profile-001-03.png", "반갑습니다 내친소 여러분!", "ESTJ", "열정적인 \uD83D\uDD25,지적인 \uD83E\uDDD0,상냥한 ☺️", "무교", "비흡연자", "같이 취미를 즐길 수 있는 연애를 하고 싶어") + Arrays.asList("01011111111", 1998, Gender.M, "허시준", "edu-image001.jpg", "서강", "대학교", "컴퓨터공학과", "1~3년", "CMC에서 만남", "착함", "\"패션센스 \uD83E\uDDE5\", \"사랑꾼 \uD83D\uDC97\", \"애교쟁이 \uD83D\uDE18\"", "자기 일을 진짜 책임감 있게 잘하고 주변을 늘 먼저 생각하는 친구야", "서울시 마포구", "1병", 180, "내친소 사용하기", "profile-001-01.png,profile-001-02.png,profile-001-03.png", "반갑습니다 내친소 여러분!", "ESTJ", "열정적인 \uD83D\uDD25,지적인 \uD83E\uDDD0,상냥한 ☺️", "무교", "비흡연자", "같이 취미를 즐길 수 있는 연애를 하고 싶어"), + Arrays.asList("01012222222", 1997, Gender.M, "민성진", "edu-image002.jpg", "한국", "고등학교", "자동차정비", "1~3년", "CMC에서 만남", "착함", "패션센스 \uD83E\uDDE5,사랑꾼 \uD83D\uDC97,애교쟁이 \uD83D\uDE18", "자기 일을 진짜 책임감 있게 잘하고 주변을 늘 먼저 생각하는 친구야", "서울시 마포구", "1병", 185, "내친소 사용하기", "profile-001-01.png,profile-001-02.png,profile-001-03.png", "반갑습니다 내친소 여러분!", "INFP", "열정적인 \uD83D\uDD25,지적인 \uD83E\uDDD0,상냥한 ☺️", "무교", "비흡연자", "같이 취미를 즐길 수 있는 연애를 하고 싶어"), + Arrays.asList("01013333333", 1996, Gender.M, "김상혁", "edu-image003.jpg", "서울", "대학원", "인공지능공학", "1~3년", "CMC에서 만남", "착함", "패션센스 \uD83E\uDDE5,사랑꾼 \uD83D\uDC97,애교쟁이 \uD83D\uDE18", "자기 일을 진짜 책임감 있게 잘하고 주변을 늘 먼저 생각하는 친구야", "서울시 마포구", "1병", 182, "내친소 사용하기", "profile-001-01.png,profile-001-02.png,profile-001-03.png", "반갑습니다 내친소 여러분!", "ESTJ", "열정적인 \uD83D\uDD25,지적인 \uD83E\uDDD0,상냥한 ☺️", "기독교", "비흡연자", "같이 취미를 즐길 수 있는 연애를 하고 싶어"), + Arrays.asList("01014444444", 1995, Gender.M, "권영성", "edu-image004.jpg", "홍익", "대학교", "시각디자인학과", "1~3년", "CMC에서 만남", "착함", "패션센스 \uD83E\uDDE5,사랑꾼 \uD83D\uDC97,애교쟁이 \uD83D\uDE18", "자기 일을 진짜 책임감 있게 잘하고 주변을 늘 먼저 생각하는 친구야", "서울시 마포구", "1병", 183, "내친소 사용하기", "profile-001-01.png,profile-001-02.png,profile-001-03.png", "반갑습니다 내친소 여러분!", "INFJ", "열정적인 \uD83D\uDD25,지적인 \uD83E\uDDD0,상냥한 ☺️", "불교", "비흡연자", "같이 취미를 즐길 수 있는 연애를 하고 싶어"), + Arrays.asList("01015555555", 1994, Gender.M, "배규빈", "edu-image005.jpg", "한성", "고등학교", "상업", "3~5년", "CMC에서 만남", "착함", "패션센스 \uD83E\uDDE5,사랑꾼 \uD83D\uDC97,애교쟁이 \uD83D\uDE18", "자기 일을 진짜 책임감 있게 잘하고 주변을 늘 먼저 생각하는 친구야", "서울시 마포구", "1병", 178, "내친소 사용하기", "profile-001-01.png,profile-001-02.png,profile-001-03.png", "반갑습니다 내친소 여러분!", "ESTJ", "열정적인 \uD83D\uDD25,지적인 \uD83E\uDDD0,상냥한 ☺️", "무교", "비흡연자", "같이 취미를 즐길 수 있는 연애를 하고 싶어"), + Arrays.asList("01016666666", 1993, Gender.M, "권민기", "edu-image006.jpg", "서울", "고등학교", "디자인", "3~5년", "CMC에서 만남", "착함", "패션센스 \uD83E\uDDE5,사랑꾼 \uD83D\uDC97,애교쟁이 \uD83D\uDE18", "자기 일을 진짜 책임감 있게 잘하고 주변을 늘 먼저 생각하는 친구야", "서울시 마포구", "1병", 172, "내친소 사용하기", "profile-001-01.png,profile-001-02.png,profile-001-03.png", "반갑습니다 내친소 여러분!", "ESFJ", "열정적인 \uD83D\uDD25,지적인 \uD83E\uDDD0,상냥한 ☺️", "무교", "비흡연자", "같이 취미를 즐길 수 있는 연애를 하고 싶어"), + Arrays.asList("01017777777", 1992, Gender.M, "김민성", "edu-image007.jpg", "연세", "대학원", "영어영문학과", "1~3년", "CMC에서 만남", "착함", "패션센스 \uD83E\uDDE5,사랑꾼 \uD83D\uDC97,애교쟁이 \uD83D\uDE18", "자기 일을 진짜 책임감 있게 잘하고 주변을 늘 먼저 생각하는 친구야", "서울시 마포구", "1병", 173, "내친소 사용하기", "profile-001-01.png,profile-001-02.png,profile-001-03.png", "반갑습니다 내친소 여러분!", "ENFP", "열정적인 \uD83D\uDD25,지적인 \uD83E\uDDD0,상냥한 ☺️", "기독교", "비흡연자", "같이 취미를 즐길 수 있는 연애를 하고 싶어"), + Arrays.asList("01018888888", 1991, Gender.M, "임정혁", "edu-image008.jpg", "연세", "대학교", "전기전자공학과", "1~3년", "CMC에서 만남", "착함", "패션센스 \uD83E\uDDE5,사랑꾼 \uD83D\uDC97,애교쟁이 \uD83D\uDE18", "자기 일을 진짜 책임감 있게 잘하고 주변을 늘 먼저 생각하는 친구야", "서울시 마포구", "1병", 175, "내친소 사용하기", "profile-001-01.png,profile-001-02.png,profile-001-03.png", "반갑습니다 내친소 여러분!", "ESTJ", "열정적인 \uD83D\uDD25,지적인 \uD83E\uDDD0,상냥한 ☺️", "무교", "비흡연자", "같이 취미를 즐길 수 있는 연애를 하고 싶어"), + Arrays.asList("01019999999", 1990, Gender.M, "성재오", "edu-image009.jpg", "이대부속", "고등학교", "공학", "1~3년", "CMC에서 만남", "착함", "패션센스 \uD83E\uDDE5,사랑꾼 \uD83D\uDC97,애교쟁이 \uD83D\uDE18", "자기 일을 진짜 책임감 있게 잘하고 주변을 늘 먼저 생각하는 친구야", "서울시 마포구", "1병", 168, "내친소 사용하기", "profile-001-01.png,profile-001-02.png,profile-001-03.png", "반갑습니다 내친소 여러분!", "ESTJ", "열정적인 \uD83D\uDD25,지적인 \uD83E\uDDD0,상냥한 ☺️", "무교", "비흡연자", "같이 취미를 즐길 수 있는 연애를 하고 싶어"), + Arrays.asList("01010000000", 1989, Gender.M, "차재훈", "edu-image010.jpg", "국민", "대학교", "미디어학과", "1~3년", "CMC에서 만남", "착함", "패션센스 \uD83E\uDDE5,사랑꾼 \uD83D\uDC97,애교쟁이 \uD83D\uDE18", "자기 일을 진짜 책임감 있게 잘하고 주변을 늘 먼저 생각하는 친구야", "서울시 마포구", "1병", 176, "내친소 사용하기", "profile-001-01.png,profile-001-02.png,profile-001-03.png", "반갑습니다 내친소 여러분!", "ESTP", "열정적인 \uD83D\uDD25,지적인 \uD83E\uDDD0,상냥한 ☺️", "무교", "비흡연자", "같이 취미를 즐길 수 있는 연애를 하고 싶어"), + + Arrays.asList("01022200000", 1998, Gender.W, "민장효", "edu-image011.jpg", "서강", "대학원", "물류학과", "1~3년", "CMC에서 만남", "착함", "패션센스 \uD83E\uDDE5,사랑꾼 \uD83D\uDC97,애교쟁이 \uD83D\uDE18", "자기 일을 진짜 책임감 있게 잘하고 주변을 늘 먼저 생각하는 친구야", "서울시 마포구", "1병", 160, "내친소 사용하기", "profile-001-01.png,profile-001-02.png,profile-001-03.png", "반갑습니다 내친소 여러분!", "INFP", "열정적인 \uD83D\uDD25,지적인 \uD83E\uDDD0,상냥한 ☺️", "무교", "비흡연자", "같이 취미를 즐길 수 있는 연애를 하고 싶어"), + Arrays.asList("01022211111", 1998, Gender.W, "김민서", "edu-image012.jpg", "홍익", "대학교", "조소과", "1~3년", "CMC에서 만남", "착함", "패션센스 \uD83E\uDDE5,사랑꾼 \uD83D\uDC97,애교쟁이 \uD83D\uDE18", "자기 일을 진짜 책임감 있게 잘하고 주변을 늘 먼저 생각하는 친구야", "서울시 마포구", "1병", 162, "내친소 사용하기", "profile-001-01.png,profile-001-02.png,profile-001-03.png", "반갑습니다 내친소 여러분!", "ESTJ", "열정적인 \uD83D\uDD25,지적인 \uD83E\uDDD0,상냥한 ☺️", "무교", "비흡연자", "같이 취미를 즐길 수 있는 연애를 하고 싶어"), + Arrays.asList("01022222222", 1998, Gender.W, "노혜지", "edu-image013.jpg", "한국", "고등학교", "디자인", "1~3년", "CMC에서 만남", "착함", "패션센스 \uD83E\uDDE5,사랑꾼 \uD83D\uDC97,애교쟁이 \uD83D\uDE18", "자기 일을 진짜 책임감 있게 잘하고 주변을 늘 먼저 생각하는 친구야", "서울시 마포구", "1병", 165, "내친소 사용하기", "profile-001-01.png,profile-001-02.png,profile-001-03.png", "반갑습니다 내친소 여러분!", "ENFP", "열정적인 \uD83D\uDD25,지적인 \uD83E\uDDD0,상냥한 ☺️", "기독교", "비흡연자", "같이 취미를 즐길 수 있는 연애를 하고 싶어"), + Arrays.asList("01022233333", 1998, Gender.W, "류라해", "edu-image014.jpg", "이화여자", "대학교", "사이버보안학과", "1~3년", "CMC에서 만남", "착함", "패션센스 \uD83E\uDDE5,사랑꾼 \uD83D\uDC97,애교쟁이 \uD83D\uDE18", "자기 일을 진짜 책임감 있게 잘하고 주변을 늘 먼저 생각하는 친구야", "서울시 마포구", "1병", 155, "내친소 사용하기", "profile-001-01.png,profile-001-02.png,profile-001-03.png", "반갑습니다 내친소 여러분!", "ESTJ", "열정적인 \uD83D\uDD25,지적인 \uD83E\uDDD0,상냥한 ☺️", "기독교", "비흡연자", "같이 취미를 즐길 수 있는 연애를 하고 싶어"), + Arrays.asList("01022244444", 1998, Gender.W, "민예지", "edu-image015.jpg", "이화여자", "대학교", "국어국문학과", "3~5년", "CMC에서 만남", "착함", "패션센스 \uD83E\uDDE5,사랑꾼 \uD83D\uDC97,애교쟁이 \uD83D\uDE18", "자기 일을 진짜 책임감 있게 잘하고 주변을 늘 먼저 생각하는 친구야", "서울시 마포구", "1병", 150, "내친소 사용하기", "profile-001-01.png,profile-001-02.png,profile-001-03.png", "반갑습니다 내친소 여러분!", "INFJ", "열정적인 \uD83D\uDD25,지적인 \uD83E\uDDD0,상냥한 ☺️", "무교", "비흡연자", "같이 취미를 즐길 수 있는 연애를 하고 싶어"), + Arrays.asList("01022255555", 1998, Gender.W, "류유주", "edu-image016.jpg", "한국", "고등학교", "공학", "1~3년", "CMC에서 만남", "착함", "패션센스 \uD83E\uDDE5,사랑꾼 \uD83D\uDC97,애교쟁이 \uD83D\uDE18", "자기 일을 진짜 책임감 있게 잘하고 주변을 늘 먼저 생각하는 친구야", "서울시 마포구", "1병", 174, "내친소 사용하기", "profile-001-01.png,profile-001-02.png,profile-001-03.png", "반갑습니다 내친소 여러분!", "INTP", "열정적인 \uD83D\uDD25,지적인 \uD83E\uDDD0,상냥한 ☺️", "기독교", "비흡연자", "같이 취미를 즐길 수 있는 연애를 하고 싶어"), + Arrays.asList("01022266666", 1998, Gender.W, "임혜서", "edu-image017.jpg", "서울", "대학원", "법학과", "1~3년", "CMC에서 만남", "착함", "패션센스 \uD83E\uDDE5,사랑꾼 \uD83D\uDC97,애교쟁이 \uD83D\uDE18", "자기 일을 진짜 책임감 있게 잘하고 주변을 늘 먼저 생각하는 친구야", "서울시 마포구", "1병", 172, "내친소 사용하기", "profile-001-01.png,profile-001-02.png,profile-001-03.png", "반갑습니다 내친소 여러분!", "ESTJ", "열정적인 \uD83D\uDD25,지적인 \uD83E\uDDD0,상냥한 ☺️", "불교", "비흡연자", "같이 취미를 즐길 수 있는 연애를 하고 싶어"), + Arrays.asList("01022277777", 1998, Gender.W, "임한하", "edu-image018.jpg", "서울", "대학교", "의상학과", "3~5년", "CMC에서 만남", "착함", "패션센스 \uD83E\uDDE5,사랑꾼 \uD83D\uDC97,애교쟁이 \uD83D\uDE18", "자기 일을 진짜 책임감 있게 잘하고 주변을 늘 먼저 생각하는 친구야", "서울시 마포구", "1병", 168, "내친소 사용하기", "profile-001-01.png,profile-001-02.png,profile-001-03.png", "반갑습니다 내친소 여러분!", "ENTP", "열정적인 \uD83D\uDD25,지적인 \uD83E\uDDD0,상냥한 ☺️", "무교", "비흡연자", "같이 취미를 즐길 수 있는 연애를 하고 싶어"), + Arrays.asList("01022288888", 1998, Gender.W, "권민영", "edu-image019.jpg", "고려", "대학교", "의학", "1~3년", "CMC에서 만남", "착함", "패션센스 \uD83E\uDDE5,사랑꾼 \uD83D\uDC97,애교쟁이 \uD83D\uDE18", "자기 일을 진짜 책임감 있게 잘하고 주변을 늘 먼저 생각하는 친구야", "서울시 마포구", "1병", 175, "내친소 사용하기", "profile-001-01.png,profile-001-02.png,profile-001-03.png", "반갑습니다 내친소 여러분!", "ESFJ", "열정적인 \uD83D\uDD25,지적인 \uD83E\uDDD0,상냥한 ☺️", "무교", "비흡연자", "같이 취미를 즐길 수 있는 연애를 하고 싶어"), + Arrays.asList("01022299999", 1998, Gender.W, "진하수", "edu-image020.jpg", "연세", "대학교", "기계공학과", "1~3년", "CMC에서 만남", "착함", "패션센스 \uD83E\uDDE5,사랑꾼 \uD83D\uDC97,애교쟁이 \uD83D\uDE18", "자기 일을 진짜 책임감 있게 잘하고 주변을 늘 먼저 생각하는 친구야", "서울시 마포구", "1병", 163, "내친소 사용하기", "profile-001-01.png,profile-001-02.png,profile-001-03.png", "반갑습니다 내친소 여러분!", "ESTJ", "열정적인 \uD83D\uDD25,지적인 \uD83E\uDDD0,상냥한 ☺️", "무교", "비흡연자", "같이 취미를 즐길 수 있는 연애를 하고 싶어") ); String accessToken = null; diff --git a/src/main/java/com/tikitaka/naechinso/domain/member/dto/MemberCommonJoinRequestDTO.java b/src/main/java/com/tikitaka/naechinso/domain/member/dto/MemberCommonJoinRequestDTO.java index 8db3e5e..03cdb09 100644 --- a/src/main/java/com/tikitaka/naechinso/domain/member/dto/MemberCommonJoinRequestDTO.java +++ b/src/main/java/com/tikitaka/naechinso/domain/member/dto/MemberCommonJoinRequestDTO.java @@ -26,9 +26,9 @@ public class MemberCommonJoinRequestDTO { @Enum(enumClass = Gender.class, message = "성별 입력이 올바르지 않습니다. M 또는 W가 필요합니다") private Gender gender; - @ApiModelProperty(example = "25") - @Min(value = 25, message = "25-35세까지만 가입 가능합니다") - @Max(value = 35, message = "25-35세까지만 가입 가능합니다") + @ApiModelProperty(example = "1998") + @Min(value = 1988, message = "1988-1998 년생까지만 가입 가능합니다") + @Max(value = 1998, message = "1988-1998 년생까지만 가입 가능합니다") private int age; @NotNull(message = "서비스 이용약관 동의가 필요합니다") diff --git a/src/main/java/com/tikitaka/naechinso/domain/member/dto/MemberDetailJoinRequestDTO.java b/src/main/java/com/tikitaka/naechinso/domain/member/dto/MemberDetailJoinRequestDTO.java index 1c54873..931afd9 100644 --- a/src/main/java/com/tikitaka/naechinso/domain/member/dto/MemberDetailJoinRequestDTO.java +++ b/src/main/java/com/tikitaka/naechinso/domain/member/dto/MemberDetailJoinRequestDTO.java @@ -28,9 +28,9 @@ public class MemberDetailJoinRequestDTO { @Enum(enumClass = Gender.class, message = "성별 입력이 올바르지 않습니다. M 또는 W가 필요합니다") private Gender gender; - @ApiModelProperty(example = "25") - @Min(value = 25, message = "25-35세까지만 가입 가능합니다") - @Max(value = 35, message = "25-35세까지만 가입 가능합니다") + @ApiModelProperty(example = "1998") + @Min(value = 1988, message = "1988-1998 년생까지만 가입 가능합니다") + @Max(value = 1998, message = "1988-1998 년생까지만 가입 가능합니다") private int age; @ApiModelProperty(example = "180") diff --git a/src/main/java/com/tikitaka/naechinso/domain/member/dto/MemberUpdateCommonRequestDTO.java b/src/main/java/com/tikitaka/naechinso/domain/member/dto/MemberUpdateCommonRequestDTO.java index 5ea3810..6789d4f 100644 --- a/src/main/java/com/tikitaka/naechinso/domain/member/dto/MemberUpdateCommonRequestDTO.java +++ b/src/main/java/com/tikitaka/naechinso/domain/member/dto/MemberUpdateCommonRequestDTO.java @@ -23,8 +23,8 @@ public class MemberUpdateCommonRequestDTO { @Enum(enumClass = Gender.class, message = "성별 입력이 올바르지 않습니다. M 또는 W가 필요합니다") private Gender gender; - @ApiModelProperty(example = "25") - @Min(value = 25, message = "25-35세까지만 가입 가능합니다") - @Max(value = 35, message = "25-35세까지만 가입 가능합니다") + @ApiModelProperty(example = "1998") + @Min(value = 1988, message = "1988-1998 년생까지만 가입 가능합니다") + @Max(value = 1998, message = "1988-1998 년생까지만 가입 가능합니다") private int age; } From 61ad4b1f1de0deeae0a79d4e0eb0577e837ce831 Mon Sep 17 00:00:00 2001 From: gengminy Date: Sat, 5 Nov 2022 15:18:49 +0900 Subject: [PATCH 62/72] =?UTF-8?q?:hammer:=20fix(recommend):=20=EC=B6=94?= =?UTF-8?q?=EC=B2=9C=EC=82=AC=20=EB=82=98=EC=9D=B4=20=ED=95=84=EB=93=9C=20?= =?UTF-8?q?dto=20=EB=B3=80=EA=B2=BD=20#39?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../recommend/dto/RecommendBySenderRequestDTO.java | 6 +++--- .../dto/RecommendMemberAcceptAndUpdateRequestDTO.java | 11 ----------- 2 files changed, 3 insertions(+), 14 deletions(-) diff --git a/src/main/java/com/tikitaka/naechinso/domain/recommend/dto/RecommendBySenderRequestDTO.java b/src/main/java/com/tikitaka/naechinso/domain/recommend/dto/RecommendBySenderRequestDTO.java index 3c46158..6620cbc 100644 --- a/src/main/java/com/tikitaka/naechinso/domain/recommend/dto/RecommendBySenderRequestDTO.java +++ b/src/main/java/com/tikitaka/naechinso/domain/recommend/dto/RecommendBySenderRequestDTO.java @@ -30,9 +30,9 @@ public class RecommendBySenderRequestDTO { @Enum(enumClass = Gender.class, message = "친구의 성별 입력이 올바르지 않습니다. M 또는 W가 필요합니다") private Gender gender; - @ApiModelProperty(example = "25") - @Min(value = 25, message = "25-35세까지만 추천 및 가입 가능합니다") - @Max(value = 35, message = "25-35세까지만 추천 및 가입 가능합니다") + @ApiModelProperty(example = "1998") + @Min(value = 1988, message = "1988-1998 년생까지만 가입 가능합니다") + @Max(value = 1998, message = "1988-1998 년생까지만 가입 가능합니다") private int age; @ApiModelProperty(example = "CMC 에서") diff --git a/src/main/java/com/tikitaka/naechinso/domain/recommend/dto/RecommendMemberAcceptAndUpdateRequestDTO.java b/src/main/java/com/tikitaka/naechinso/domain/recommend/dto/RecommendMemberAcceptAndUpdateRequestDTO.java index eefac82..897b51e 100644 --- a/src/main/java/com/tikitaka/naechinso/domain/recommend/dto/RecommendMemberAcceptAndUpdateRequestDTO.java +++ b/src/main/java/com/tikitaka/naechinso/domain/recommend/dto/RecommendMemberAcceptAndUpdateRequestDTO.java @@ -22,17 +22,6 @@ public class RecommendMemberAcceptAndUpdateRequestDTO { @ApiModelProperty private MemberUpdateJobRequestDTO job; -// @NotBlank(message = "직장명을 입력해주세요") -// private String jobName; -// -// @ApiModelProperty(example = "개발자") -// @NotBlank(message = "직장 부서를 입력해주세요") -// private String jobPart; -// -// @ApiModelProperty(example = "판교") -// @NotBlank(message = "직장 위치를 입력해주세요") -// private String jobLocation; - @ApiModelProperty(example = "CMC 에서") @NotBlank(message = "만나게 된 계기를 입력해주세요") private String meet; From a5cbcb388ea4a80e43bbb469e9cb609de89b6771 Mon Sep 17 00:00:00 2001 From: gengminy Date: Sat, 5 Nov 2022 20:16:14 +0900 Subject: [PATCH 63/72] =?UTF-8?q?:rocket:=20feat(match):=20=EB=A7=A4?= =?UTF-8?q?=EC=B9=AD=20=EC=8A=A4=EC=BC=80=EC=A5=B4=EB=A7=81=20=EA=B8=B0?= =?UTF-8?q?=EB=8A=A5=20=EA=B5=AC=ED=98=84=20#64?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../naechinso/NaechinsoApplication.java | 4 +++- .../naechinso/domain/TestController.java | 24 +++++++++++++++++++ .../naechinso/domain/card/CardRepository.java | 2 ++ .../naechinso/domain/card/CardService.java | 5 ++-- .../domain/match/MatchRepository.java | 5 ++++ .../naechinso/domain/match/MatchService.java | 21 ++++++++++++++++ .../domain/match/constant/MatchStatus.java | 1 - .../naechinso/domain/match/entity/Match.java | 9 ++++++- 8 files changed, 66 insertions(+), 5 deletions(-) diff --git a/src/main/java/com/tikitaka/naechinso/NaechinsoApplication.java b/src/main/java/com/tikitaka/naechinso/NaechinsoApplication.java index 9d9d689..48e5674 100644 --- a/src/main/java/com/tikitaka/naechinso/NaechinsoApplication.java +++ b/src/main/java/com/tikitaka/naechinso/NaechinsoApplication.java @@ -3,9 +3,11 @@ import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.data.jpa.repository.config.EnableJpaAuditing; +import org.springframework.scheduling.annotation.EnableScheduling; -@SpringBootApplication +@EnableScheduling //scheduler 사용 @EnableJpaAuditing //jpa entity 자동 감시 +@SpringBootApplication public class NaechinsoApplication { public static void main(String[] args) { SpringApplication.run(NaechinsoApplication.class, args); diff --git a/src/main/java/com/tikitaka/naechinso/domain/TestController.java b/src/main/java/com/tikitaka/naechinso/domain/TestController.java index f908558..1f83e76 100644 --- a/src/main/java/com/tikitaka/naechinso/domain/TestController.java +++ b/src/main/java/com/tikitaka/naechinso/domain/TestController.java @@ -2,6 +2,7 @@ import com.tikitaka.naechinso.domain.card.CardRepository; import com.tikitaka.naechinso.domain.card.CardService; +import com.tikitaka.naechinso.domain.card.entity.Card; import com.tikitaka.naechinso.domain.match.MatchRepository; import com.tikitaka.naechinso.domain.match.MatchService; import com.tikitaka.naechinso.domain.match.constant.MatchStatus; @@ -485,6 +486,29 @@ public CommonApiResponse createMatch( return CommonApiResponse.of(MatchResponseDTO.of(match)); } + @GetMapping("/create-match-in-row") + @ApiOperation(value = "[*TEST*] accessToken 의 유저가 소유한 매칭 정보를 10 개 무작위 생성한다") + public CommonApiResponse createCardInRowEight( + @ApiIgnore @AuthMember Member member + ) { + Member findMember = memberService.findByMember(member); + List matchList = List.of( + Match.builder().fromMember(findMember).toMember(findMember).isExpired(false).status(MatchStatus.ACCEPTED).build(), + Match.builder().fromMember(findMember).toMember(findMember).isExpired(false).status(MatchStatus.OPEN).build(), + Match.builder().fromMember(findMember).toMember(findMember).isExpired(false).status(MatchStatus.OPEN).build(), + Match.builder().fromMember(findMember).toMember(findMember).isExpired(false).status(MatchStatus.ACCEPTED).build(), + Match.builder().fromMember(findMember).toMember(findMember).isExpired(false).status(MatchStatus.PENDING).build(), + Match.builder().fromMember(findMember).toMember(findMember).isExpired(false).status(MatchStatus.PENDING).build(), + Match.builder().fromMember(findMember).toMember(findMember).isExpired(false).status(MatchStatus.PENDING).build(), + Match.builder().fromMember(findMember).toMember(findMember).isExpired(false).status(MatchStatus.PENDING).build(), + Match.builder().fromMember(findMember).toMember(findMember).isExpired(false).status(MatchStatus.PENDING).build(), + Match.builder().fromMember(findMember).toMember(findMember).isExpired(false).status(MatchStatus.PENDING).build() + ); + + matchRepository.saveAllAndFlush(matchList); + return CommonApiResponse.of(matchList); + } + @DeleteMapping("/drop-all-table") @ApiOperation(value = "[*TEST*] 모든 DB 테이블을 초기화") public CommonApiResponse dropAllTable(){ diff --git a/src/main/java/com/tikitaka/naechinso/domain/card/CardRepository.java b/src/main/java/com/tikitaka/naechinso/domain/card/CardRepository.java index ea71fb6..2a9fe47 100644 --- a/src/main/java/com/tikitaka/naechinso/domain/card/CardRepository.java +++ b/src/main/java/com/tikitaka/naechinso/domain/card/CardRepository.java @@ -20,6 +20,8 @@ public interface CardRepository extends JpaRepository { long countByMemberAndCreatedAtBetween(Member member, LocalDateTime start, LocalDateTime end); + List findAllByIsActiveTrue(); + @Query("select c.targetMemberId " + "from Card c " + "where c.targetMemberId <> :id") diff --git a/src/main/java/com/tikitaka/naechinso/domain/card/CardService.java b/src/main/java/com/tikitaka/naechinso/domain/card/CardService.java index 546102f..301be6b 100644 --- a/src/main/java/com/tikitaka/naechinso/domain/card/CardService.java +++ b/src/main/java/com/tikitaka/naechinso/domain/card/CardService.java @@ -11,8 +11,10 @@ import com.tikitaka.naechinso.global.error.ErrorCode; import com.tikitaka.naechinso.global.error.exception.BadRequestException; import com.tikitaka.naechinso.global.error.exception.NotFoundException; +import com.tikitaka.naechinso.global.util.DateUtil; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; +import org.springframework.scheduling.annotation.Scheduled; import org.springframework.stereotype.Service; import java.time.LocalDate; @@ -30,7 +32,6 @@ public class CardService { private final CardRepository cardRepository; private final MemberRepository memberRepository; - /** * 내가 받았던 모든 카드 기록을 가져온다 (챗봇 썸네일용) */ @@ -138,7 +139,7 @@ public Card findByMemberAndIsActiveTrue(Member member) { } /** - * 오늘 날짜를 기준으로 + * 오늘 날짜를 기준으로 하루동안 받은 카드 개수 반환 * */ private long countCardByMemberAndCreatedAtBetween(Member member) { //서버 시간으로 00시00분부터 23시59분까지받은 카드 수 종합 diff --git a/src/main/java/com/tikitaka/naechinso/domain/match/MatchRepository.java b/src/main/java/com/tikitaka/naechinso/domain/match/MatchRepository.java index 551b2f1..d33dfc0 100644 --- a/src/main/java/com/tikitaka/naechinso/domain/match/MatchRepository.java +++ b/src/main/java/com/tikitaka/naechinso/domain/match/MatchRepository.java @@ -1,5 +1,6 @@ package com.tikitaka.naechinso.domain.match; +import com.tikitaka.naechinso.domain.card.entity.Card; import com.tikitaka.naechinso.domain.match.constant.MatchStatus; import com.tikitaka.naechinso.domain.match.dto.MatchResponseDTO; import com.tikitaka.naechinso.domain.match.entity.Match; @@ -7,6 +8,7 @@ import org.springframework.data.jpa.repository.JpaRepository; import org.springframework.data.jpa.repository.Query; +import java.time.LocalDateTime; import java.util.List; import java.util.Optional; @@ -64,6 +66,9 @@ public interface MatchRepository extends JpaRepository { Optional findByIdAndToMemberAndStatus(Long id, Member member, MatchStatus status); + /** time 이전의 not expired 된 모든 카드를 가져옴 */ + List findAllByIsExpiredFalseAndCreatedAtBefore(LocalDateTime time); + Optional findByIdAndStatus(Long id, MatchStatus status); // @Query("select new com.tikitaka.naechinso.domain.match.dto.MatchResponseDTO(mat, m1, m2) " + diff --git a/src/main/java/com/tikitaka/naechinso/domain/match/MatchService.java b/src/main/java/com/tikitaka/naechinso/domain/match/MatchService.java index 34dea74..3c53fc8 100644 --- a/src/main/java/com/tikitaka/naechinso/domain/match/MatchService.java +++ b/src/main/java/com/tikitaka/naechinso/domain/match/MatchService.java @@ -21,9 +21,13 @@ import lombok.extern.slf4j.Slf4j; import org.apache.commons.lang3.StringUtils; import org.springframework.context.ApplicationEventPublisher; +import org.springframework.scheduling.annotation.Scheduled; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; +import java.time.LocalDate; +import java.time.LocalDateTime; +import java.time.LocalTime; import java.util.List; import java.util.stream.Collectors; @@ -38,6 +42,8 @@ public class MatchService { private final CardRepository cardRepository; private final ApplicationEventPublisher applicationEventPublisher; + int EXPIRY_DATE_DAY = 3; + /** * 활성화된 카드에 해당하는 상대에게 호감을 보낸다 * @param authMember @@ -225,4 +231,19 @@ public MatchOpenProfileResponseDTO getOpenProfileById(Member authMember, Long id public MatchListResponseDTO findAllByMember(Member authMember) { return MatchListResponseDTO.of(authMember); } + + /** + * 매일 00시00분 마다 기간이 지난 카드 자동 만료 + */ + @Scheduled(cron = "0 0 0 * * ?") //daily at 00:00 + protected void scheduleTask() { + //현재 시간으로 부터 3일 전의 00시 00분 이전 시각 + LocalDateTime compareDateTime = LocalDateTime.of(LocalDate.now().minusDays(EXPIRY_DATE_DAY), LocalTime.of(0,0,0)); + //그 이전의 카드는 만료되었으므로 모두 가져옴 + List matchList = matchRepository.findAllByIsExpiredFalseAndCreatedAtBefore(compareDateTime); + //만료 + matchList.forEach(Match::expire); + log.info("Scheduling System Automatically Expire Matches :: Affected Matches Count - {}", matchList.size()); + matchRepository.saveAll(matchList); + } } diff --git a/src/main/java/com/tikitaka/naechinso/domain/match/constant/MatchStatus.java b/src/main/java/com/tikitaka/naechinso/domain/match/constant/MatchStatus.java index bd95d92..b2999b5 100644 --- a/src/main/java/com/tikitaka/naechinso/domain/match/constant/MatchStatus.java +++ b/src/main/java/com/tikitaka/naechinso/domain/match/constant/MatchStatus.java @@ -1,7 +1,6 @@ package com.tikitaka.naechinso.domain.match.constant; public enum MatchStatus { - EXPIRED, //기간(7일) 만료 WAIT, //호감 보내기 전 상태 PENDING, //호감을 보낸 상태 ACCEPTED, //상대가 승낙 diff --git a/src/main/java/com/tikitaka/naechinso/domain/match/entity/Match.java b/src/main/java/com/tikitaka/naechinso/domain/match/entity/Match.java index 5132d9d..f38b818 100644 --- a/src/main/java/com/tikitaka/naechinso/domain/match/entity/Match.java +++ b/src/main/java/com/tikitaka/naechinso/domain/match/entity/Match.java @@ -15,7 +15,6 @@ @AllArgsConstructor @NoArgsConstructor @ToString(exclude = {"fromMember", "toMember"}) -@EqualsAndHashCode public class Match extends BaseEntity { @Id @Column(name = "mat_id") @@ -27,6 +26,10 @@ public class Match extends BaseEntity { @Builder.Default private MatchStatus status = MatchStatus.WAIT; + @Column(name = "mat_is_expired") + @Builder.Default + private Boolean isExpired = false; + /* 호감을 보내는 사람 */ @ManyToOne(fetch = FetchType.LAZY) @JoinColumn(name = "mem_from_id") @@ -39,6 +42,10 @@ public class Match extends BaseEntity { @JsonIgnore private Member toMember; + /* 만료 */ + public void expire() { + this.isExpired = true; + } /* 호감 거절 */ public void reject() { this.status = MatchStatus.REJECTED; From 8b445a33e977b6a3e7bb3483d4417dbe87d37c29 Mon Sep 17 00:00:00 2001 From: gengminy Date: Sat, 5 Nov 2022 20:54:13 +0900 Subject: [PATCH 64/72] =?UTF-8?q?:hammer:=20fix(match):=20=EB=A7=A4?= =?UTF-8?q?=EC=B9=AD=20=EB=A7=8C=EB=A3=8C=EC=97=90=20=EB=8C=80=ED=95=9C=20?= =?UTF-8?q?=EB=B0=98=ED=99=98=EA=B0=92=20=EB=B0=8F=20=EC=98=A4=EB=A5=98=20?= =?UTF-8?q?=EB=B3=80=EA=B2=BD=20#64?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../domain/match/MatchRepository.java | 8 +- .../naechinso/domain/match/MatchService.java | 74 +++++++++++-------- .../match/dto/MatchThumbnailResponseDTO.java | 14 +--- .../naechinso/global/error/ErrorCode.java | 1 + 4 files changed, 51 insertions(+), 46 deletions(-) diff --git a/src/main/java/com/tikitaka/naechinso/domain/match/MatchRepository.java b/src/main/java/com/tikitaka/naechinso/domain/match/MatchRepository.java index d33dfc0..17235f5 100644 --- a/src/main/java/com/tikitaka/naechinso/domain/match/MatchRepository.java +++ b/src/main/java/com/tikitaka/naechinso/domain/match/MatchRepository.java @@ -54,15 +54,15 @@ public interface MatchRepository extends JpaRepository { @Query("SELECT CASE WHEN COUNT(m) > 0 THEN 'true' ELSE 'false' END " + "FROM Match m " + "JOIN m.fromMember f JOIN m.toMember t " + - "WHERE f.id = :id OR t.id = :id") - Boolean existsByTargetId(Long id); + "WHERE f.id = :id OR t.id = :id AND m.isExpired = false") + Boolean existsByTargetIdAndIsExpiredFalse(Long id); @Query("SELECT CASE WHEN COUNT(m) > 0 THEN 'true' ELSE 'false' END " + "FROM Match m " + "JOIN m.fromMember f JOIN m.toMember t " + - "WHERE (f.id = :id OR t.id = :id) " + + "WHERE (f.id = :id OR t.id = :id) AND m.isExpired = false " + "AND m.status = com.tikitaka.naechinso.domain.match.constant.MatchStatus.OPEN") - Boolean existsByTargetIdAndStatusIsOpen(Long id); + Boolean existsByTargetIdAndIsExpiredFalseAndStatusIsOpen(Long id); Optional findByIdAndToMemberAndStatus(Long id, Member member, MatchStatus status); diff --git a/src/main/java/com/tikitaka/naechinso/domain/match/MatchService.java b/src/main/java/com/tikitaka/naechinso/domain/match/MatchService.java index 3c53fc8..645e6d6 100644 --- a/src/main/java/com/tikitaka/naechinso/domain/match/MatchService.java +++ b/src/main/java/com/tikitaka/naechinso/domain/match/MatchService.java @@ -86,6 +86,10 @@ public MatchResponseDTO like(Member authMember) { public MatchResponseDTO reject(Member authMember, Long matchId) { Match match = matchRepository.findByIdAndToMemberAndStatus(matchId, authMember, MatchStatus.PENDING) .orElseThrow(() -> new NotFoundException(ErrorCode.MATCH_NOT_FOUND)); + //만료된 매칭 + if (match.getIsExpired()) { + throw new BadRequestException(ErrorCode.EXPIRED_MATCH); + } Member fromMember = match.getFromMember(); @@ -114,6 +118,10 @@ public MatchResponseDTO reject(Member authMember, Long matchId) { public MatchResponseDTO accept(Member authMember, Long matchId) { Match match = matchRepository.findByIdAndToMemberAndStatus(matchId, authMember, MatchStatus.PENDING) .orElseThrow(() -> new NotFoundException(ErrorCode.MATCH_NOT_FOUND)); + //만료된 매칭 + if (match.getIsExpired()) { + throw new BadRequestException(ErrorCode.EXPIRED_MATCH); + } Member fromMember = match.getFromMember(); @@ -142,6 +150,10 @@ public MatchResponseDTO accept(Member authMember, Long matchId) { public MatchResponseDTO openPhone(Member authMember, Long matchId) { Match match = matchRepository.findByIdAndStatus(matchId, MatchStatus.ACCEPTED) .orElseThrow(() -> new NotFoundException(ErrorCode.MATCH_NOT_FOUND)); + //만료된 매칭 + if (match.getIsExpired()) { + throw new BadRequestException(ErrorCode.EXPIRED_MATCH); + } //유저에게 속하지 않은 매칭에 대한 유효하지 않은 요청 if (!match.getFromMember().getId().equals(authMember.getId()) @@ -164,6 +176,36 @@ public MatchResponseDTO openPhone(Member authMember, Long matchId) { } + /** + * 호감 주거나 받은 상대의 프로필 정보를 가져옴 + * */ + public MatchBasicProfileResponseDTO getBasicProfileById(Member authMember, Long id) { + //관련 매칭 정보가 없으면 403 + if(!matchRepository.existsByTargetIdAndIsExpiredFalse(id)){ + throw new ForbiddenException(ErrorCode.FORBIDDEN_PROFILE); + } + + Member oppositeMember = memberRepository.findByMember(authMember) + .orElseThrow(() -> new NotFoundException(ErrorCode.USER_NOT_FOUND)); + + return MatchBasicProfileResponseDTO.of(oppositeMember); + } + + /** + * 호감 주거나 받은 상대의 프로필 정보를 가져옴 + * */ + public MatchOpenProfileResponseDTO getOpenProfileById(Member authMember, Long id) { + //OPEN 상태인 매칭 정보가 없다면 에러 + if(!matchRepository.existsByTargetIdAndIsExpiredFalseAndStatusIsOpen(id)){ + throw new ForbiddenException(ErrorCode.FORBIDDEN_PROFILE); + } + + Member oppositeMember = memberRepository.findByMember(authMember) + .orElseThrow(() -> new NotFoundException(ErrorCode.USER_NOT_FOUND)); + + return MatchOpenProfileResponseDTO.of(oppositeMember); + } + /** * 호감을 받은 매칭 정보를 모두 가져온다 * @param authMember @@ -197,41 +239,11 @@ public List findAllByMatchComplete(Member authMember) .collect(Collectors.toList()); } - - /** - * 호감 주거나 받은 상대의 프로필 정보를 가져옴 - * */ - public MatchBasicProfileResponseDTO getBasicProfileById(Member authMember, Long id) { - //관련 매칭 정보가 없으면 403 - if(!matchRepository.existsByTargetId(id)){ - throw new ForbiddenException(ErrorCode.FORBIDDEN_PROFILE); - } - - Member oppositeMember = memberRepository.findByMember(authMember) - .orElseThrow(() -> new NotFoundException(ErrorCode.USER_NOT_FOUND)); - - return MatchBasicProfileResponseDTO.of(oppositeMember); - } - - /** - * 호감 주거나 받은 상대의 프로필 정보를 가져옴 - * */ - public MatchOpenProfileResponseDTO getOpenProfileById(Member authMember, Long id) { - //OPEN 상태인 매칭 정보가 없다면 에러 - if(!matchRepository.existsByTargetIdAndStatusIsOpen(id)){ - throw new ForbiddenException(ErrorCode.FORBIDDEN_PROFILE); - } - - Member oppositeMember = memberRepository.findByMember(authMember) - .orElseThrow(() -> new NotFoundException(ErrorCode.USER_NOT_FOUND)); - - return MatchOpenProfileResponseDTO.of(oppositeMember); - } - public MatchListResponseDTO findAllByMember(Member authMember) { return MatchListResponseDTO.of(authMember); } + /** * 매일 00시00분 마다 기간이 지난 카드 자동 만료 */ diff --git a/src/main/java/com/tikitaka/naechinso/domain/match/dto/MatchThumbnailResponseDTO.java b/src/main/java/com/tikitaka/naechinso/domain/match/dto/MatchThumbnailResponseDTO.java index 4e93279..1a92a4f 100644 --- a/src/main/java/com/tikitaka/naechinso/domain/match/dto/MatchThumbnailResponseDTO.java +++ b/src/main/java/com/tikitaka/naechinso/domain/match/dto/MatchThumbnailResponseDTO.java @@ -30,7 +30,7 @@ public class MatchThumbnailResponseDTO { @Builder.Default private long dueDate = 0L; - private List images; + private String image; private String name; private int age; private String address; @@ -39,7 +39,6 @@ public class MatchThumbnailResponseDTO { private String jobName; private String jobPart; private String jobLocation; - private String eduName; private String eduMajor; private String eduLevel; @@ -62,10 +61,6 @@ private static class Recommendation { private String eduName; private String eduMajor; private String eduLevel; - - private String meet; - private String period; - private String appealDetail; } public static MatchThumbnailResponseDTO of(Match match, Member member) { @@ -86,7 +81,7 @@ public static MatchThumbnailResponseDTO of(Match match, Member member) { .status(match.getStatus()) .createdAt(match.getCreatedAt().toString()) .dueDate(generateDueDate(match.getCreatedAt())) - .images(dto.getImages()) + .image(dto.getImages() != null ? dto.getImages().get(0) : null) .name(dto.getName()) .age(dto.getAge()) .address(dto.getAddress()) @@ -107,15 +102,12 @@ public static MatchThumbnailResponseDTO of(Match match, Member member) { .eduName(dto.getRecommend().getEduName()) .eduMajor(dto.getRecommend().getEduMajor()) .eduLevel(dto.getRecommend().getEduLevel()) - .meet(dto.getRecommend().getMeet()) - .period(dto.getRecommend().getPeriod()) - .appealDetail(dto.getRecommend().getAppealDetail()) .build()) .build(); } private static long generateDueDate(LocalDateTime createdAt) { - LocalDateTime endDatetime = LocalDateTime.of(createdAt.toLocalDate().plusDays(7), LocalTime.of(23,59,59)); + LocalDateTime endDatetime = LocalDateTime.of(createdAt.toLocalDate().plusDays(3), LocalTime.of(23,59,59)); long dueDate = Duration.between(LocalDateTime.now(), endDatetime).toDays(); if (dueDate < 0) { return 0; diff --git a/src/main/java/com/tikitaka/naechinso/global/error/ErrorCode.java b/src/main/java/com/tikitaka/naechinso/global/error/ErrorCode.java index 8d49274..0c4ed80 100644 --- a/src/main/java/com/tikitaka/naechinso/global/error/ErrorCode.java +++ b/src/main/java/com/tikitaka/naechinso/global/error/ErrorCode.java @@ -84,6 +84,7 @@ public enum ErrorCode { MATCH_ALREADY_OPEN(BAD_REQUEST, "MATCH002", "이미 번호 오픈권을 사용했습니다"), MATCH_ALREADY_ACCEPTED(BAD_REQUEST, "MATCH002", "이미 호감을 수락했습니다"), BAD_MATCH_STATUS(BAD_REQUEST, "MATCH003", "매칭 상태 정보가 유효하지 않습니다"), + EXPIRED_MATCH(BAD_REQUEST, "MATCH004", "매칭 상태가 만료되었습니다"), /* Validation 오류 */ PARAMETER_NOT_VALID(BAD_REQUEST, "P000", "인자가 유효하지 않습니다"), From 699d74df55f5c2a64d2b9559bba24cf5562d635a Mon Sep 17 00:00:00 2001 From: gengminy Date: Sat, 5 Nov 2022 22:19:43 +0900 Subject: [PATCH 65/72] =?UTF-8?q?:hammer:=20fix(member):=20=EB=A9=A4?= =?UTF-8?q?=EB=B2=84=20=EC=8A=B9=EC=9D=B8=20=EB=A1=9C=EC=A7=81=20=EC=9E=84?= =?UTF-8?q?=EC=8B=9C=20=EB=B3=80=EA=B2=BD=20#43?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../domain/member/MemberService.java | 31 ++++++++++++++++--- 1 file changed, 27 insertions(+), 4 deletions(-) diff --git a/src/main/java/com/tikitaka/naechinso/domain/member/MemberService.java b/src/main/java/com/tikitaka/naechinso/domain/member/MemberService.java index 291cc43..454498b 100644 --- a/src/main/java/com/tikitaka/naechinso/domain/member/MemberService.java +++ b/src/main/java/com/tikitaka/naechinso/domain/member/MemberService.java @@ -207,7 +207,12 @@ public MemberDetailResponseDTO createDetail(Member authMember, MemberDetailJoinR memberDetailRepository.save(detail); member.setDetail(detail); - pendingService.createPendingByMemberImage(member, new MemberUpdateImageRequestDTO(dto.getImages())); + + /** 임시 정책 221105 */ +// pendingService.createPendingByMemberImage(member, new MemberUpdateImageRequestDTO(dto.getImages())); + member.updateImage(dto.getImages()); + /** 임시 정책 221105 */ + return MemberDetailResponseDTO.of(detail); } } @@ -222,7 +227,13 @@ public MemberDetailResponseDTO createDetail(Member authMember, MemberDetailJoinR * */ public MemberCommonResponseDTO updateJobRequest(Member authMember, MemberUpdateJobRequestDTO dto){ //직업 정보 승인 요청 - return pendingService.createPendingByJob(authMember, dto); +// return pendingService.createPendingByJob(authMember, dto); + /** 임시 정책 221105 */ + Member member = memberRepository.findByMember(authMember) + .orElseThrow(() -> new NotFoundException(ErrorCode.USER_NOT_FOUND)); + member.updateJob(dto); + return MemberCommonResponseDTO.of(member); + /** 임시 정책 221105 */ } /** @@ -231,7 +242,13 @@ public MemberCommonResponseDTO updateJobRequest(Member authMember, MemberUpdateJ * */ public MemberCommonResponseDTO updateEduRequest(Member authMember, MemberUpdateEduRequestDTO dto){ //학력 정보 승인 요청 - return pendingService.createPendingByEdu(authMember, dto); +// return pendingService.createPendingByEdu(authMember, dto); + /** 임시 정책 221105 */ + Member member = memberRepository.findByMember(authMember) + .orElseThrow(() -> new NotFoundException(ErrorCode.USER_NOT_FOUND)); + member.updateEdu(dto); + return MemberCommonResponseDTO.of(member); + /** 임시 정책 221105 */ } /** @@ -248,7 +265,13 @@ public MemberAcceptsResponseDTO updateAccepts(Member authMember, MemberUpdateAcc * MemberDetail 의 프로필 이미지를 업로드 한다 * */ public MemberDetailResponseDTO updateImage(Member authMember, MemberUpdateImageRequestDTO dto){ - return pendingService.createPendingByMemberImage(authMember, dto); + /** 임시 정책 221105 */ +// return pendingService.createPendingByMemberImage(authMember, dto); + Member member = memberRepository.findByMember(authMember) + .orElseThrow(() -> new NotFoundException(ErrorCode.USER_NOT_FOUND)); + member.updateImage(dto.getImages()); + return MemberDetailResponseDTO.of(member); + /** 임시 정책 221105 */ } /** From 0cedb423b9399483d97ec3a2098e53526d4cd921 Mon Sep 17 00:00:00 2001 From: gengminy Date: Sun, 6 Nov 2022 11:55:21 +0900 Subject: [PATCH 66/72] =?UTF-8?q?:hammer:=20fix(card):=20=EC=B9=B4?= =?UTF-8?q?=EB=93=9C=20=EC=8D=B8=EB=84=A4=EC=9D=BC=20=EC=A0=95=EB=B3=B4=20?= =?UTF-8?q?=EB=B3=80=EA=B2=BD=20#71?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../com/tikitaka/naechinso/domain/card/CardController.java | 2 +- .../java/com/tikitaka/naechinso/domain/card/CardService.java | 4 ++-- .../naechinso/domain/card/dto/CardThumbnailResponseDTO.java | 5 +++-- 3 files changed, 6 insertions(+), 5 deletions(-) diff --git a/src/main/java/com/tikitaka/naechinso/domain/card/CardController.java b/src/main/java/com/tikitaka/naechinso/domain/card/CardController.java index ede0aca..c31c89e 100644 --- a/src/main/java/com/tikitaka/naechinso/domain/card/CardController.java +++ b/src/main/java/com/tikitaka/naechinso/domain/card/CardController.java @@ -24,7 +24,7 @@ public class CardController { @GetMapping @ApiOperation(value = "자신이 소유한 모든 카드 썸네일을 가져온다 (AccessToken)") - public CommonApiResponse> getAllCardsByMember( + public CommonApiResponse> getAllCardsByMember( @ApiIgnore @AuthMember Member member ) { return CommonApiResponse.of(cardService.findAllCard(member)); diff --git a/src/main/java/com/tikitaka/naechinso/domain/card/CardService.java b/src/main/java/com/tikitaka/naechinso/domain/card/CardService.java index 301be6b..50d1853 100644 --- a/src/main/java/com/tikitaka/naechinso/domain/card/CardService.java +++ b/src/main/java/com/tikitaka/naechinso/domain/card/CardService.java @@ -35,7 +35,7 @@ public class CardService { /** * 내가 받았던 모든 카드 기록을 가져온다 (챗봇 썸네일용) */ - public List findAllCard(Member authMember){ + public List findAllCard(Member authMember){ return cardRepository.findAllByMember(authMember).stream().map( card -> { Member targetMember = memberRepository.findById(card.getTargetMemberId()) @@ -44,7 +44,7 @@ public List findAllCard(Member authMember) if (targetMember == null) { return null; } - return CardOppositeMemberProfileResponseDTO.of(targetMember); + return CardThumbnailResponseDTO.of(card, targetMember); } ).collect(Collectors.toList()); } diff --git a/src/main/java/com/tikitaka/naechinso/domain/card/dto/CardThumbnailResponseDTO.java b/src/main/java/com/tikitaka/naechinso/domain/card/dto/CardThumbnailResponseDTO.java index 901d7b0..74188cf 100644 --- a/src/main/java/com/tikitaka/naechinso/domain/card/dto/CardThumbnailResponseDTO.java +++ b/src/main/java/com/tikitaka/naechinso/domain/card/dto/CardThumbnailResponseDTO.java @@ -27,7 +27,7 @@ public class CardThumbnailResponseDTO { @Builder.Default private long dueDate = 0L; - private List images; + private String image; private String name; private int age; private String address; @@ -72,13 +72,14 @@ public static CardThumbnailResponseDTO of(Card card, Member targetMember) { //상대 프로필 dto 에서 가져옴 MemberOppositeProfileResponseDTO dto = MemberOppositeProfileResponseDTO.of(targetMember); + String topImage = targetMember.getDetail().getImages() != null ? targetMember.getDetail().getImages().get(0) : null; return CardThumbnailResponseDTO.builder() .targetMemberId(card.getTargetMemberId()) .isActive(card.getIsActive()) .createdAt(card.getCreatedAt().toString()) .dueDate(DateUtil.getDueDay(card.getCreatedAt(), 7L)) - .images(targetMember.getDetail().getImages()) + .image(topImage) .name(dto.getName()) .age(dto.getAge()) .address(dto.getAddress()) From 25428e69aac4531cee1001d76b08bdfb4406750b Mon Sep 17 00:00:00 2001 From: gengminy Date: Sun, 6 Nov 2022 11:58:48 +0900 Subject: [PATCH 67/72] =?UTF-8?q?:hammer:=20fix(card):=20due=20date=20?= =?UTF-8?q?=ED=94=84=EB=A1=9C=ED=8D=BC=ED=8B=B0=20=EC=82=AD=EC=A0=9C=20#71?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../naechinso/domain/card/dto/CardThumbnailResponseDTO.java | 4 ---- 1 file changed, 4 deletions(-) diff --git a/src/main/java/com/tikitaka/naechinso/domain/card/dto/CardThumbnailResponseDTO.java b/src/main/java/com/tikitaka/naechinso/domain/card/dto/CardThumbnailResponseDTO.java index 74188cf..d80b0e3 100644 --- a/src/main/java/com/tikitaka/naechinso/domain/card/dto/CardThumbnailResponseDTO.java +++ b/src/main/java/com/tikitaka/naechinso/domain/card/dto/CardThumbnailResponseDTO.java @@ -24,9 +24,6 @@ public class CardThumbnailResponseDTO { private Boolean isActive; private String createdAt; - @Builder.Default - private long dueDate = 0L; - private String image; private String name; private int age; @@ -78,7 +75,6 @@ public static CardThumbnailResponseDTO of(Card card, Member targetMember) { .targetMemberId(card.getTargetMemberId()) .isActive(card.getIsActive()) .createdAt(card.getCreatedAt().toString()) - .dueDate(DateUtil.getDueDay(card.getCreatedAt(), 7L)) .image(topImage) .name(dto.getName()) .age(dto.getAge()) From fa85ece4e0ac20e12bf2195d6863fc31f985657b Mon Sep 17 00:00:00 2001 From: gengminy Date: Mon, 7 Nov 2022 00:45:12 +0900 Subject: [PATCH 68/72] =?UTF-8?q?:hammer:=20fix(recommend):=20=EC=B6=94?= =?UTF-8?q?=EC=B2=9C=EC=9D=B8=20=EC=9D=B8=EC=A6=9D=20=EC=98=A4=EB=A5=98=20?= =?UTF-8?q?=EC=88=98=EC=A0=95=20#73?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../tikitaka/naechinso/domain/member/MemberService.java | 4 ++++ .../tikitaka/naechinso/domain/member/entity/Member.java | 9 +++++++++ .../naechinso/domain/recommend/RecommendService.java | 3 +-- .../naechinso/domain/recommend/entity/Recommend.java | 6 +++++- 4 files changed, 19 insertions(+), 3 deletions(-) diff --git a/src/main/java/com/tikitaka/naechinso/domain/member/MemberService.java b/src/main/java/com/tikitaka/naechinso/domain/member/MemberService.java index 454498b..16a5b8c 100644 --- a/src/main/java/com/tikitaka/naechinso/domain/member/MemberService.java +++ b/src/main/java/com/tikitaka/naechinso/domain/member/MemberService.java @@ -148,6 +148,10 @@ public MemberCommonJoinResponseDTO joinCommonMember(String phone, MemberCommonJo Member member = MemberCommonJoinRequestDTO.toCommonMember(phone, dto); memberRepository.save(member); + //내 번호로 받았던 추천서 저장 + List recommendList = recommendRepository.findAllByReceiverPhone(phone); + recommendList.forEach(recommend -> recommend.setReceiver(member)); + TokenResponseDTO tokenResponseDTO = jwtTokenProvider.generateToken(new JwtDTO(phone, "ROLE_USER")); diff --git a/src/main/java/com/tikitaka/naechinso/domain/member/entity/Member.java b/src/main/java/com/tikitaka/naechinso/domain/member/entity/Member.java index c48cb64..e88c213 100644 --- a/src/main/java/com/tikitaka/naechinso/domain/member/entity/Member.java +++ b/src/main/java/com/tikitaka/naechinso/domain/member/entity/Member.java @@ -195,6 +195,15 @@ public void setDeleted(){ @Builder.Default private List cards = new ArrayList<>(); + + public void addRecommend(Recommend recommend) { + this.recommends.add(recommend); + } + + public void addRecommendReceived(Recommend recommend) { + this.recommendReceived.add(recommend); + } + public void setDetail(MemberDetail memberDetail) { this.detail = memberDetail; } diff --git a/src/main/java/com/tikitaka/naechinso/domain/recommend/RecommendService.java b/src/main/java/com/tikitaka/naechinso/domain/recommend/RecommendService.java index 1d7ffd4..b6256a4 100644 --- a/src/main/java/com/tikitaka/naechinso/domain/recommend/RecommendService.java +++ b/src/main/java/com/tikitaka/naechinso/domain/recommend/RecommendService.java @@ -143,8 +143,7 @@ public RecommendResponseDTO acceptRecommendByUuid(Member authMember, String uuid throw new BadRequestException(ErrorCode.CANNOT_RECOMMEND_MYSELF); } - //추천사 업데이트 - recommend.update(dto); + recommend.update(sender, dto); recommendRepository.save(recommend); return RecommendResponseDTO.of(recommend); diff --git a/src/main/java/com/tikitaka/naechinso/domain/recommend/entity/Recommend.java b/src/main/java/com/tikitaka/naechinso/domain/recommend/entity/Recommend.java index 4d477d6..22735a9 100644 --- a/src/main/java/com/tikitaka/naechinso/domain/recommend/entity/Recommend.java +++ b/src/main/java/com/tikitaka/naechinso/domain/recommend/entity/Recommend.java @@ -104,8 +104,12 @@ public class Recommend extends BaseEntity { @Column(name = "rec_period") private String receiverPeriod; + public void setReceiver(Member receiver) { + this.receiver = receiver; + } - public void update(RecommendAcceptRequestDTO requestDTO) { + public void update(Member sender, RecommendAcceptRequestDTO requestDTO) { + this.sender = sender; this.receiverAppeals = StringUtils.join(requestDTO.getAppeals(), ","); this.receiverAppealDetail = requestDTO.getAppealDetail(); this.receiverMeet = requestDTO.getMeet(); From 96e2355ed4978207e153f97d4e5b3f73d3e7578c Mon Sep 17 00:00:00 2001 From: gengminy Date: Tue, 8 Nov 2022 13:23:48 +0900 Subject: [PATCH 69/72] =?UTF-8?q?:hammer:=20fix(match):=20=EB=A7=A4?= =?UTF-8?q?=EC=B9=AD=20=EC=83=81=EB=8C=80=20=ED=94=84=EB=A1=9C=ED=95=84=20?= =?UTF-8?q?=EA=B0=80=EC=A0=B8=EC=98=A4=EA=B8=B0=20=EC=98=A4=EB=A5=98=20?= =?UTF-8?q?=EC=88=98=EC=A0=95=20#75?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../naechinso/domain/match/MatchRepository.java | 10 ++++++++-- .../naechinso/domain/match/MatchService.java | 16 +++++++++++----- 2 files changed, 19 insertions(+), 7 deletions(-) diff --git a/src/main/java/com/tikitaka/naechinso/domain/match/MatchRepository.java b/src/main/java/com/tikitaka/naechinso/domain/match/MatchRepository.java index 17235f5..85b2cf1 100644 --- a/src/main/java/com/tikitaka/naechinso/domain/match/MatchRepository.java +++ b/src/main/java/com/tikitaka/naechinso/domain/match/MatchRepository.java @@ -51,11 +51,17 @@ public interface MatchRepository extends JpaRepository { "AND m.status = com.tikitaka.naechinso.domain.match.constant.MatchStatus.ACCEPTED") Optional findAllByIdAndMemberAndStatusIsAccept(Long id, Member member); - @Query("SELECT CASE WHEN COUNT(m) > 0 THEN 'true' ELSE 'false' END " + +// @Query("SELECT CASE WHEN COUNT(m) > 0 THEN 'true' ELSE 'false' END " + +// "FROM Match m " + +// "JOIN m.fromMember f JOIN m.toMember t " + +// "WHERE f.id = :id OR t.id = :id AND m.isExpired = false") +// Boolean existsByTargetIdAndIsExpiredFalse(Long id); + + @Query("SELECT m " + "FROM Match m " + "JOIN m.fromMember f JOIN m.toMember t " + "WHERE f.id = :id OR t.id = :id AND m.isExpired = false") - Boolean existsByTargetIdAndIsExpiredFalse(Long id); + Optional findByTargetIdAndIsExpiredFalse(Long id); @Query("SELECT CASE WHEN COUNT(m) > 0 THEN 'true' ELSE 'false' END " + "FROM Match m " + diff --git a/src/main/java/com/tikitaka/naechinso/domain/match/MatchService.java b/src/main/java/com/tikitaka/naechinso/domain/match/MatchService.java index 645e6d6..88ccdbe 100644 --- a/src/main/java/com/tikitaka/naechinso/domain/match/MatchService.java +++ b/src/main/java/com/tikitaka/naechinso/domain/match/MatchService.java @@ -181,14 +181,20 @@ public MatchResponseDTO openPhone(Member authMember, Long matchId) { * */ public MatchBasicProfileResponseDTO getBasicProfileById(Member authMember, Long id) { //관련 매칭 정보가 없으면 403 - if(!matchRepository.existsByTargetIdAndIsExpiredFalse(id)){ - throw new ForbiddenException(ErrorCode.FORBIDDEN_PROFILE); - } + Match match = matchRepository.findByTargetIdAndIsExpiredFalse(id) + .orElseThrow(() -> new ForbiddenException(ErrorCode.FORBIDDEN_PROFILE)); - Member oppositeMember = memberRepository.findByMember(authMember) + //내정보 가져오기 + Member member = memberRepository.findByMember(authMember) .orElseThrow(() -> new NotFoundException(ErrorCode.USER_NOT_FOUND)); - return MatchBasicProfileResponseDTO.of(oppositeMember); + if (match.getFromMember() != null && match.getFromMember() == member) { + return MatchBasicProfileResponseDTO.of(match.getToMember()); + } else if (match.getToMember() != null && match.getToMember() == member){ + return MatchBasicProfileResponseDTO.of(match.getFromMember()); + } else { + throw new BadRequestException(ErrorCode.BAD_MATCH_STATUS); + } } /** From 689381b366f93f4fbc462c6bfc4b5643264f4148 Mon Sep 17 00:00:00 2001 From: gengminy Date: Tue, 8 Nov 2022 13:29:35 +0900 Subject: [PATCH 70/72] =?UTF-8?q?:hammer:=20fix(match):=20=EB=B2=88?= =?UTF-8?q?=ED=98=B8=20=EC=98=A4=ED=94=88=20=EC=83=81=EB=8C=80=20=ED=94=84?= =?UTF-8?q?=EB=A1=9C=ED=95=84=20=EA=B0=80=EC=A0=B8=EC=98=A4=EA=B8=B0=20?= =?UTF-8?q?=EC=98=A4=EB=A5=98=20=EC=88=98=EC=A0=95=20#75?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../naechinso/domain/match/MatchRepository.java | 11 +++++++++-- .../naechinso/domain/match/MatchService.java | 15 ++++++++++----- 2 files changed, 19 insertions(+), 7 deletions(-) diff --git a/src/main/java/com/tikitaka/naechinso/domain/match/MatchRepository.java b/src/main/java/com/tikitaka/naechinso/domain/match/MatchRepository.java index 85b2cf1..d2de7e8 100644 --- a/src/main/java/com/tikitaka/naechinso/domain/match/MatchRepository.java +++ b/src/main/java/com/tikitaka/naechinso/domain/match/MatchRepository.java @@ -63,12 +63,19 @@ public interface MatchRepository extends JpaRepository { "WHERE f.id = :id OR t.id = :id AND m.isExpired = false") Optional findByTargetIdAndIsExpiredFalse(Long id); - @Query("SELECT CASE WHEN COUNT(m) > 0 THEN 'true' ELSE 'false' END " + +// @Query("SELECT CASE WHEN COUNT(m) > 0 THEN 'true' ELSE 'false' END " + +// "FROM Match m " + +// "JOIN m.fromMember f JOIN m.toMember t " + +// "WHERE (f.id = :id OR t.id = :id) AND m.isExpired = false " + +// "AND m.status = com.tikitaka.naechinso.domain.match.constant.MatchStatus.OPEN") +// Boolean existsByTargetIdAndIsExpiredFalseAndStatusIsOpen(Long id); + + @Query("SELECT m " + "FROM Match m " + "JOIN m.fromMember f JOIN m.toMember t " + "WHERE (f.id = :id OR t.id = :id) AND m.isExpired = false " + "AND m.status = com.tikitaka.naechinso.domain.match.constant.MatchStatus.OPEN") - Boolean existsByTargetIdAndIsExpiredFalseAndStatusIsOpen(Long id); + Optional findByTargetIdAndIsExpiredFalseAndStatusIsOpen(Long id); Optional findByIdAndToMemberAndStatus(Long id, Member member, MatchStatus status); diff --git a/src/main/java/com/tikitaka/naechinso/domain/match/MatchService.java b/src/main/java/com/tikitaka/naechinso/domain/match/MatchService.java index 88ccdbe..9350d66 100644 --- a/src/main/java/com/tikitaka/naechinso/domain/match/MatchService.java +++ b/src/main/java/com/tikitaka/naechinso/domain/match/MatchService.java @@ -202,14 +202,19 @@ public MatchBasicProfileResponseDTO getBasicProfileById(Member authMember, Long * */ public MatchOpenProfileResponseDTO getOpenProfileById(Member authMember, Long id) { //OPEN 상태인 매칭 정보가 없다면 에러 - if(!matchRepository.existsByTargetIdAndIsExpiredFalseAndStatusIsOpen(id)){ - throw new ForbiddenException(ErrorCode.FORBIDDEN_PROFILE); - } + Match match = matchRepository.findByTargetIdAndIsExpiredFalseAndStatusIsOpen(id) + .orElseThrow(() -> new ForbiddenException(ErrorCode.FORBIDDEN_PROFILE)); - Member oppositeMember = memberRepository.findByMember(authMember) + Member member = memberRepository.findByMember(authMember) .orElseThrow(() -> new NotFoundException(ErrorCode.USER_NOT_FOUND)); - return MatchOpenProfileResponseDTO.of(oppositeMember); + if (match.getFromMember() != null && match.getFromMember() == member) { + return MatchOpenProfileResponseDTO.of(match.getToMember()); + } else if (match.getToMember() != null && match.getToMember() == member){ + return MatchOpenProfileResponseDTO.of(match.getFromMember()); + } else { + throw new BadRequestException(ErrorCode.BAD_MATCH_STATUS); + } } /** From 86e71200fcea0c09b7da5d0c6d64a74adc634205 Mon Sep 17 00:00:00 2001 From: gengminy Date: Wed, 9 Nov 2022 23:34:50 +0900 Subject: [PATCH 71/72] =?UTF-8?q?:hammer:=20fix(recommend):=20=EA=B0=80?= =?UTF-8?q?=EC=9E=85=20=EC=8B=9C=20=EC=B6=94=EC=B2=9C=EC=82=AC=EC=97=90?= =?UTF-8?q?=EC=84=9C=20=EC=9E=98=EB=AA=BB=EB=90=9C=20=EC=B6=94=EC=B2=9C?= =?UTF-8?q?=EC=9D=B8=20=EC=A0=95=EB=B3=B4=20=EC=98=A4=EB=A5=98=20=EC=88=98?= =?UTF-8?q?=EC=A0=95=20#78?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../domain/recommend/dto/RecommendReceiverDTO.java | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/main/java/com/tikitaka/naechinso/domain/recommend/dto/RecommendReceiverDTO.java b/src/main/java/com/tikitaka/naechinso/domain/recommend/dto/RecommendReceiverDTO.java index 795e54a..b050cfc 100644 --- a/src/main/java/com/tikitaka/naechinso/domain/recommend/dto/RecommendReceiverDTO.java +++ b/src/main/java/com/tikitaka/naechinso/domain/recommend/dto/RecommendReceiverDTO.java @@ -29,9 +29,9 @@ public static RecommendReceiverDTO of(Recommend recommend) { throw new BadRequestException(ErrorCode.RECOMMEND_SENDER_NOT_EXIST); } return RecommendReceiverDTO.builder() - .name(recommend.getSenderName()) - .gender(recommend.getSenderGender()) - .age(recommend.getSenderAge()) + .name(recommend.getReceiverName()) + .gender(recommend.getReceiverGender()) + .age(recommend.getReceiverAge()) .senderCreditAccepted(recommend.getSender().getEduAccepted() || recommend.getSender().getJobAccepted() ) .build(); } From f273908359fc1ea9ea2ab01b0ffc90ba5b912fde Mon Sep 17 00:00:00 2001 From: gengminy Date: Thu, 10 Nov 2022 01:41:23 +0900 Subject: [PATCH 72/72] =?UTF-8?q?:hammer:=20fix(recommend):=20=EC=9D=91?= =?UTF-8?q?=EB=8B=B5=20DTO=EC=97=90=20=EC=B6=94=EC=B2=9C=EC=9D=B8=EC=9D=98?= =?UTF-8?q?=20=EC=9D=B4=EB=A6=84=20=EC=B6=94=EA=B0=80=20#80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../member/dto/MemberCommonResponseDTO.java | 1 + .../domain/recommend/RecommendService.java | 6 +++--- .../recommend/dto/RecommendResponseDTO.java | 6 ++++++ .../domain/recommend/entity/Recommend.java | 21 ++++++++++++------- 4 files changed, 23 insertions(+), 11 deletions(-) diff --git a/src/main/java/com/tikitaka/naechinso/domain/member/dto/MemberCommonResponseDTO.java b/src/main/java/com/tikitaka/naechinso/domain/member/dto/MemberCommonResponseDTO.java index e480194..333c75e 100644 --- a/src/main/java/com/tikitaka/naechinso/domain/member/dto/MemberCommonResponseDTO.java +++ b/src/main/java/com/tikitaka/naechinso/domain/member/dto/MemberCommonResponseDTO.java @@ -5,6 +5,7 @@ import com.tikitaka.naechinso.domain.member.entity.Member; import com.tikitaka.naechinso.domain.pending.dto.PendingFindResponseDTO; import com.tikitaka.naechinso.domain.pending.entity.Pending; +import com.tikitaka.naechinso.domain.recommend.entity.Recommend; import io.swagger.annotations.ApiModelProperty; import lombok.*; diff --git a/src/main/java/com/tikitaka/naechinso/domain/recommend/RecommendService.java b/src/main/java/com/tikitaka/naechinso/domain/recommend/RecommendService.java index b6256a4..5aeb1d7 100644 --- a/src/main/java/com/tikitaka/naechinso/domain/recommend/RecommendService.java +++ b/src/main/java/com/tikitaka/naechinso/domain/recommend/RecommendService.java @@ -75,9 +75,9 @@ public RecommendResponseDTO createRecommend(Member authMember, RecommendBySender .senderName(sender.getName()) .senderAge(sender.getAge()) .senderGender(sender.getGender()) - .senderJobName(sender.getJobName()) - .senderJobPart(sender.getJobPart()) - .senderJobLocation(sender.getJobLocation()) +// .senderJobName(sender.getJobName()) +// .senderJobPart(sender.getJobPart()) +// .senderJobLocation(sender.getJobLocation()) .receiver(receiver) .receiverPhone(dto.getPhone()) .receiverName(dto.getName()) diff --git a/src/main/java/com/tikitaka/naechinso/domain/recommend/dto/RecommendResponseDTO.java b/src/main/java/com/tikitaka/naechinso/domain/recommend/dto/RecommendResponseDTO.java index 79e232b..474f34c 100644 --- a/src/main/java/com/tikitaka/naechinso/domain/recommend/dto/RecommendResponseDTO.java +++ b/src/main/java/com/tikitaka/naechinso/domain/recommend/dto/RecommendResponseDTO.java @@ -31,6 +31,8 @@ public class RecommendResponseDTO { private String period; + private String senderName; + private Long senderId; private Long receiverId; @@ -38,11 +40,14 @@ public class RecommendResponseDTO { public static RecommendResponseDTO of(Recommend recommend) { Long senderId; + String senderName; Long receiverId; if (recommend.getSender() == null) { senderId = null; + senderName = null; } else { senderId = recommend.getSender().getId(); + senderName = recommend.getSenderName(); } if (recommend.getReceiver() == null) { @@ -55,6 +60,7 @@ public static RecommendResponseDTO of(Recommend recommend) { .uuid(recommend.getUuid()) .phone(recommend.getReceiverPhone()) .senderId(senderId) + .senderName(senderName) .receiverId(receiverId) .name(recommend.getReceiverName()) .gender(recommend.getReceiverGender()) diff --git a/src/main/java/com/tikitaka/naechinso/domain/recommend/entity/Recommend.java b/src/main/java/com/tikitaka/naechinso/domain/recommend/entity/Recommend.java index 22735a9..a24e597 100644 --- a/src/main/java/com/tikitaka/naechinso/domain/recommend/entity/Recommend.java +++ b/src/main/java/com/tikitaka/naechinso/domain/recommend/entity/Recommend.java @@ -53,14 +53,14 @@ public class Recommend extends BaseEntity { @Column(name = "mem_age") private int senderAge; - @Column(name = "mem_job_name") - private String senderJobName; - - @Column(name = "mem_job_part") - private String senderJobPart; - - @Column(name = "mem_job_location") - private String senderJobLocation; +// @Column(name = "mem_job_name") +// private String senderJobName; +// +// @Column(name = "mem_job_part") +// private String senderJobPart; +// +// @Column(name = "mem_job_location") +// private String senderJobLocation; // @Column(name = "mem_edu_name") @@ -110,6 +110,11 @@ public void setReceiver(Member receiver) { public void update(Member sender, RecommendAcceptRequestDTO requestDTO) { this.sender = sender; + this.senderPhone = sender.getPhone(); + this.senderName = sender.getName(); + this.senderPhone = sender.getPhone(); + this.senderAge = sender.getAge(); + this.senderGender = sender.getGender(); this.receiverAppeals = StringUtils.join(requestDTO.getAppeals(), ","); this.receiverAppealDetail = requestDTO.getAppealDetail(); this.receiverMeet = requestDTO.getMeet();