Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix: 회원이 가지고 있는 만료되지 않은 쿠폰에 대한 브랜드 리스트 조회 API 개발 #17

Merged
merged 13 commits into from
Aug 4, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,8 @@

import com.example.couphoneserver.common.annotation.NoAuth;
import com.example.couphoneserver.common.response.BaseResponse;
import com.example.couphoneserver.dto.member.request.LoginRequestDto;
import com.example.couphoneserver.dto.member.response.LoginResponseDto;
import com.example.couphoneserver.dto.auth.LoginRequestDto;
import com.example.couphoneserver.dto.auth.LoginResponseDto;
import com.example.couphoneserver.service.MemberService;
import io.swagger.v3.oas.annotations.Operation;
import lombok.RequiredArgsConstructor;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,15 +1,13 @@
package com.example.couphoneserver.controller;

import com.example.couphoneserver.common.annotation.NoAuth;
import com.example.couphoneserver.common.response.BaseResponse;
import com.example.couphoneserver.domain.entity.Member;
import com.example.couphoneserver.dto.member.request.AddMemberRequestDto;
import com.example.couphoneserver.dto.member.response.MemberInfoResponseDto;
import com.example.couphoneserver.dto.member.response.MemberResponseDto;
import com.example.couphoneserver.dto.member.response.GetMemberCouponBrandsResponse;
import com.example.couphoneserver.dto.member.response.GetMemberResponse;
import com.example.couphoneserver.dto.member.response.PatchMemberResponse;
import com.example.couphoneserver.service.MemberService;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.tags.Tag;
import jakarta.validation.Valid;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.web.bind.annotation.*;
Expand All @@ -22,27 +20,34 @@
public class MemberController {
private final MemberService memberService;

@NoAuth
@PostMapping
@Operation(summary = "이메일으로 회원 가입", description =
"Request Body 에 이메일, 비밀번호를 담아서 보내면 비밀번호는 DB 에 암호화되어 관리합니다.")
public BaseResponse<MemberResponseDto> signup(@Valid @RequestBody AddMemberRequestDto request) {
return new BaseResponse<>(memberService.save(request));
}

@PatchMapping("/{member-id}")
@Operation(summary = "회원 탈퇴", description =
"회원의 상태를 TERMINATED 으로 변경합니다. path variable 로 멤버 id 담아서 보내주세요!")
public BaseResponse<MemberResponseDto> delete(@PathVariable("member-id") Long memberId){
public BaseResponse<PatchMemberResponse> delete(@PathVariable("member-id") Long memberId) {
Member member = memberService.findOneById(memberId);
return new BaseResponse<>(memberService.delete(member));
}

@GetMapping("/{member-id}")
@Operation(summary = "회원 정보 조회", description =
"회원 정보를 조회합니다. path variable 로 멤버 id 담아서 보내주세요!")
public BaseResponse<MemberInfoResponseDto> show(@PathVariable("member-id") Long memberId){
public BaseResponse<GetMemberResponse> show(@PathVariable("member-id") Long memberId) {
Member member = memberService.findOneById(memberId);
return new BaseResponse<>(memberService.getMemberInfo(member));
}

@GetMapping("/{member-id}/brands")
@Operation(summary = "정렬 조건에 따른 브랜드 조회", description =
"""
path variable 으로 member-id 를 보내면 해당 회원이 가지고 있는 쿠폰 브랜드 리스트를 반환합니다.
정렬 조건은 query string 으로 sort 값을 보내주세요. {1, 2, 3} 에 따라 달라집니다.
- 1(default)번 옵션은 쿠폰 많은 순, 생성 시간이 이른 순
- 2번 옵션은 생성 시간이 이른 순, 쿠폰 많은 순
- 3번 옵션은 브랜드 이름 순으로 정렬하여 데이터를 반환합니다.
""")
public BaseResponse<GetMemberCouponBrandsResponse> getBrands(
@PathVariable("member-id") Long memberId,
@RequestParam(required = false, defaultValue = "1", value = "sort") String sort) {
return new BaseResponse<>(memberService.getBrands(memberId, Integer.parseInt(sort)));
}
}
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
package com.example.couphoneserver.dto.member.request;
package com.example.couphoneserver.dto.auth;

import io.swagger.v3.oas.annotations.media.Schema;
import jakarta.validation.constraints.Email;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
package com.example.couphoneserver.dto.member.response;
package com.example.couphoneserver.dto.auth;

import com.example.couphoneserver.domain.MemberGrade;
import io.swagger.v3.oas.annotations.media.Schema;
Expand Down

This file was deleted.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

이미 있는 GetBrandResponse에 쿠폰 상태, 만료 시간만 추가해서 이용해도 될 것 같아요..!

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

오! 그러네요. 저녁에 반영해보도록 하겟습니다,,,

Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
package com.example.couphoneserver.dto.member.response;

import com.example.couphoneserver.domain.CouponItemStatus;
import com.example.couphoneserver.dto.brand.GetBrandResponse;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Getter;

import java.time.LocalDateTime;

@Getter
public class BrandDto {
@Schema(description = "브랜드 정보")
GetBrandResponse brandInfo;
@Schema(description = "쿠폰 상태", example = "ACTIVE")
CouponItemStatus couponItemStatus;
@Schema(description = "만료 시간", example = "2024-01-29 18:35:46.434060")
LocalDateTime expiredDate;

public BrandDto(GetBrandResponse brand, CouponItemStatus status) {
this.expiredDate = brand.getCreatedDate().plusMonths(6);
this.couponItemStatus = status;
this.brandInfo = brand;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
package com.example.couphoneserver.dto.member.response;

import com.example.couphoneserver.domain.MemberGrade;
import com.example.couphoneserver.domain.MemberStatus;
import com.example.couphoneserver.domain.entity.Member;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Getter;

import java.util.List;

@Getter
public class GetMemberCouponBrandsResponse {
@Schema(example = "1", description = "회원 아이디")
private Long id;
@Schema(example = "김이름", description = "회원 이름")
private String name;
@Schema(example = "[email protected]", description = "이메일")
private String email;
@Schema(example = "ROLE_MEMBER", description = "회원 권한")
private MemberGrade memberGrade;
@Schema(example = "ACTIVE", description = "회원 상태")
private MemberStatus memberStatus;
@Schema(description = "회원 정보와, 회원이 가지고 있는 쿠폰에 대한 브랜드 목록을 반환")
private List<BrandDto> brandInfoList;

public GetMemberCouponBrandsResponse(Member member, List<BrandDto> brandsInfoList) {
this.id = member.getId();
this.name = member.getName();
this.email = member.getEmail();
this.memberGrade = member.getGrade();
this.memberStatus = member.getStatus();
this.brandInfoList= brandsInfoList;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@

@Getter
@NoArgsConstructor(access = AccessLevel.PROTECTED)
public class MemberInfoResponseDto {
public class GetMemberResponse {
@Schema(example = "1", description = "회원 아이디")
private Long id;
@Schema(example = "김이름", description = "회원 이름")
Expand All @@ -22,7 +22,7 @@ public class MemberInfoResponseDto {
@Schema(example = "ACTIVE", description = "회원 상태")
private MemberStatus memberStatus;

public MemberInfoResponseDto(Member member) {
public GetMemberResponse(Member member) {
id = member.getId();
name = member.getName();
email = member.getEmail();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,10 +9,10 @@

@Getter
@NoArgsConstructor(access = AccessLevel.PROTECTED)
public class MemberResponseDto {
public class PatchMemberResponse {
@Schema(example = "1", description = "회원 아이디")
private Long id;
public MemberResponseDto(Member member) {
public PatchMemberResponse(Member member) {
id = member.getId();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -20,4 +20,16 @@ public interface CouponItemRepository extends JpaRepository<CouponItem, Long> {
List<CouponItem> findAllByMemberIdAndBrandId(Long mid, Long bid);

Optional<CouponItem> findById(Long couponId);

// 특정 회원이 가지고 있는 유효한 쿠폰을 1. 도장 개수 많은 순, 2. 생성시간이 빠른 순으로 조회.
@Query("SELECT c FROM CouponItem c WHERE c.member.id = :memberId AND c.status <> 'EXPIRED' ORDER BY c.stampCount DESC, c.createdDate ASC")
List<CouponItem> findByMemberIdOrderByStampCountAndCreatedDate(@Param("memberId") Long memberId);

// 특정 회원이 가지고 있는 유효한 쿠폰을 1. 생성시간이 빠른 순, 2. 도장 개수가 많은 순으로 조회.
@Query("SELECT c FROM CouponItem c WHERE c.member.id = :memberId AND c.status <> 'EXPIRED' ORDER BY c.createdDate, c.stampCount DESC")
List<CouponItem> findByMemberIdOrderByCreatedDateAndStampCount(@Param("memberId") Long memberId);

// 특정 회원이 가지고 있는 유효한 쿠폰을 브랜드 이름으로 조회
@Query("SELECT c FROM CouponItem c WHERE c.member.id = :memberId AND c.status <> 'EXPIRED' ORDER BY c.brand.name")
List<CouponItem> findByMemberIdOrderByBrandName(@Param("memberId") Long memberId);
}
67 changes: 44 additions & 23 deletions src/main/java/com/example/couphoneserver/service/MemberService.java
Original file line number Diff line number Diff line change
Expand Up @@ -3,12 +3,17 @@
import com.example.couphoneserver.common.exception.MemberException;
import com.example.couphoneserver.domain.MemberGrade;
import com.example.couphoneserver.domain.MemberStatus;
import com.example.couphoneserver.domain.entity.CouponItem;
import com.example.couphoneserver.domain.entity.Member;
import com.example.couphoneserver.dto.member.request.AddMemberRequestDto;
import com.example.couphoneserver.dto.member.request.LoginRequestDto;
import com.example.couphoneserver.dto.member.response.LoginResponseDto;
import com.example.couphoneserver.dto.member.response.MemberInfoResponseDto;
import com.example.couphoneserver.dto.member.response.MemberResponseDto;
import com.example.couphoneserver.dto.auth.LoginRequestDto;
import com.example.couphoneserver.dto.auth.LoginResponseDto;
import com.example.couphoneserver.dto.brand.GetBrandResponse;
import com.example.couphoneserver.dto.member.response.BrandDto;
import com.example.couphoneserver.dto.member.response.GetMemberCouponBrandsResponse;
import com.example.couphoneserver.dto.member.response.GetMemberResponse;
import com.example.couphoneserver.dto.member.response.PatchMemberResponse;
import com.example.couphoneserver.repository.BrandRepository;
import com.example.couphoneserver.repository.CouponItemRepository;
import com.example.couphoneserver.repository.MemberRepository;
import com.example.couphoneserver.utils.jwt.JwtTokenProvider;
import lombok.RequiredArgsConstructor;
Expand Down Expand Up @@ -38,25 +43,14 @@
@RequiredArgsConstructor
public class MemberService {
private final MemberRepository memberRepository;
private final CouponItemRepository couponItemRepository;

private final BrandRepository brandRepository;
private final BCryptPasswordEncoder bCryptPasswordEncoder;
private final JwtTokenProvider jwtProvider;
private final AuthenticationManagerBuilder authenticationManagerBuilder;
private final RefreshTokenService refreshTokenService;

/**
* 이메일로 회원 가입
*/
@Transactional
public MemberResponseDto save(AddMemberRequestDto dto) throws UsernameNotFoundException {
validateDuplicateMemberByEmail(dto.getEmail());
validateDuplicateMemberByName(dto.getName());
Member savedMember = memberRepository.save(
new Member(dto.getName(), dto.getEmail(), bCryptPasswordEncoder.encode(dto.getPassword()),
MemberStatus.ACTIVE, MemberGrade.ROLE_MEMBER)
);
return new MemberResponseDto(savedMember);
}

@Transactional
public void saveByEmailAndName(LoginRequestDto dto) throws UsernameNotFoundException {
validateDuplicateMemberByEmail(dto.getEmail());
Expand Down Expand Up @@ -96,9 +90,9 @@ public Long join(Member member) {
* 회원 탈퇴 처리
*/
@Transactional
public MemberResponseDto delete(Member member) {
public PatchMemberResponse delete(Member member) {
member.setTerminated();
return new MemberResponseDto(member);
return new PatchMemberResponse(member);
}

@Transactional
Expand Down Expand Up @@ -131,8 +125,8 @@ public Member findOneByEmail(String email) {
/**
* 단일 회원 정보 조회
*/
public MemberInfoResponseDto getMemberInfo(Member member) {
return new MemberInfoResponseDto(member);
public GetMemberResponse getMemberInfo(Member member) {
return new GetMemberResponse(member);
}

/**
Expand Down Expand Up @@ -185,4 +179,31 @@ public Optional<Member> getMemberByEmail(String email) {
}


public GetMemberCouponBrandsResponse getBrands(Long memberId, int option) {
// 회원이 가지고 있는 쿠폰의 브랜드 정보 리스트와 회원 정보를 같이 반환합니다.
// 이때 정렬 기준은 option 에 따라서 달라집니다. (default 는 쿠폰 많은 순, 생성시간 이른 순)
List<CouponItem> coupons;
switch (option) {
case 2 -> {
log.info("[정렬 필터 옵션2번]");
coupons = couponItemRepository.findByMemberIdOrderByCreatedDateAndStampCount(memberId);
}
case 3 -> {
log.info("[정렬 필터 옵션3번]");
coupons = couponItemRepository.findByMemberIdOrderByBrandName(memberId);
}
default -> {
log.info("[정렬 필터 옵션1번]");
coupons = couponItemRepository.findByMemberIdOrderByStampCountAndCreatedDate(memberId);
}
}
List<BrandDto> brands = coupons.stream().map(coupon -> {
GetBrandResponse brandInfo = new GetBrandResponse(coupon.getBrand(), coupon.getStampCount());
return new BrandDto(brandInfo, coupon.getStatus());
}).toList();

Member member = findOneById(memberId);
return new GetMemberCouponBrandsResponse(member, brands);
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,8 @@
import com.example.couphoneserver.common.exception.MemberException;
import com.example.couphoneserver.domain.MemberStatus;
import com.example.couphoneserver.domain.entity.Member;
import com.example.couphoneserver.dto.member.request.LoginRequestDto;
import com.example.couphoneserver.dto.member.response.LoginResponseDto;
import com.example.couphoneserver.dto.auth.LoginRequestDto;
import com.example.couphoneserver.dto.auth.LoginResponseDto;
import com.example.couphoneserver.repository.BrandRepository;
import com.example.couphoneserver.repository.MemberRepository;
import com.example.couphoneserver.repository.StoreRepository;
Expand Down