diff --git a/.gitignore b/.gitignore index 29fffdc..853ec00 100644 --- a/.gitignore +++ b/.gitignore @@ -36,4 +36,5 @@ out/ ### VS Code ### .vscode/ src/main/resources/application.yml -src/main/java/team/haedal/gifticionfunding/service/OAuth2SuccessHandler.java \ No newline at end of file +src/main/java/team/haedal/gifticionfunding/service/OAuth2SuccessHandler.java +src/main/resources/dataSample.sql \ No newline at end of file diff --git a/src/main/java/team/haedal/gifticionfunding/common/DateUtils.java b/src/main/java/team/haedal/gifticionfunding/common/DateUtils.java new file mode 100644 index 0000000..8d2b968 --- /dev/null +++ b/src/main/java/team/haedal/gifticionfunding/common/DateUtils.java @@ -0,0 +1,20 @@ +package team.haedal.gifticionfunding.common; + +import java.time.LocalDate; +import java.time.LocalDateTime; +import java.time.format.DateTimeFormatter; +import java.time.temporal.ChronoUnit; + +public final class DateUtils{ + public static String dateToString(LocalDateTime localDateTime) { + return localDateTime.format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss")); + } + + + public static long diff(LocalDate start, LocalDate end){ + return ChronoUnit.DAYS.between( + LocalDate.of(1, start.getMonth(), start.getDayOfMonth()), + LocalDate.of(1, end.getMonth(), end.getDayOfMonth())); + } + +} diff --git a/src/main/java/team/haedal/gifticionfunding/config/SecurityConfig.java b/src/main/java/team/haedal/gifticionfunding/config/SecurityConfig.java index 44151aa..f241fd6 100644 --- a/src/main/java/team/haedal/gifticionfunding/config/SecurityConfig.java +++ b/src/main/java/team/haedal/gifticionfunding/config/SecurityConfig.java @@ -26,9 +26,7 @@ public class SecurityConfig { private static final String[] WHITE_LIST = { - "/api/auth/**", - "/api-docs/**", - "/login/**", + "**" }; private static final String[] AUTHENTICATION_LIST = { diff --git a/src/main/java/team/haedal/gifticionfunding/config/SwaggerConfig.java b/src/main/java/team/haedal/gifticionfunding/config/SwaggerConfig.java index 57995a4..4b21c17 100644 --- a/src/main/java/team/haedal/gifticionfunding/config/SwaggerConfig.java +++ b/src/main/java/team/haedal/gifticionfunding/config/SwaggerConfig.java @@ -3,6 +3,8 @@ import io.swagger.v3.oas.models.Components; import io.swagger.v3.oas.models.OpenAPI; import io.swagger.v3.oas.models.info.Info; +import io.swagger.v3.oas.models.security.SecurityRequirement; +import io.swagger.v3.oas.models.security.SecurityScheme; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; @@ -10,9 +12,18 @@ public class SwaggerConfig { @Bean public OpenAPI openAPI() { + String jwt = "accessToken"; + SecurityRequirement securityRequirement = new SecurityRequirement().addList(jwt); + Components components = new Components().addSecuritySchemes(jwt, new SecurityScheme() + .name(jwt) + .type(SecurityScheme.Type.HTTP) + .scheme("bearer") + .bearerFormat("JWT") + ); return new OpenAPI() - .components(new Components()) - .info(apiInfo()); + .components(components) + .info(apiInfo()) + .addSecurityItem(securityRequirement); } private Info apiInfo() { diff --git a/src/main/java/team/haedal/gifticionfunding/controller/FriendController.java b/src/main/java/team/haedal/gifticionfunding/controller/FriendController.java new file mode 100644 index 0000000..e8719e5 --- /dev/null +++ b/src/main/java/team/haedal/gifticionfunding/controller/FriendController.java @@ -0,0 +1,60 @@ +package team.haedal.gifticionfunding.controller; + +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.tags.Tag; +import lombok.RequiredArgsConstructor; +import org.springframework.http.HttpStatus; +import org.springframework.http.ResponseEntity; +import org.springframework.security.core.Authentication; +import org.springframework.web.bind.annotation.*; +import org.springframework.web.servlet.config.annotation.EnableWebMvc; +import team.haedal.gifticionfunding.dto.PageResponse; +import team.haedal.gifticionfunding.dto.response.friend.FriendResponse; +import team.haedal.gifticionfunding.service.FriendService; + +@RestController +@RequiredArgsConstructor +@EnableWebMvc +@RequestMapping("/api/friend") +@Tag(name="Friend",description="친구 관련 API") +public class FriendController { + //TODO: 친구 목록, 요청받은 친구 목록 + //TODO: 친구 요청, 요청 수락, 요청 거절, 요청 취소 + private final FriendService friendService; + + @GetMapping() + @Operation(summary = "친구 목록 조회 API") + public ResponseEntity> getFriends(Authentication authentication, + @RequestParam(value="page", defaultValue="0") int page){ + return ResponseEntity.status(HttpStatus.OK).body(friendService.getFriends(page,authentication.getName())); + } + + @PostMapping("/request") + @Operation(summary = "친구 요청 API") + public void requestFriend(Authentication authentication, + @RequestParam(name="friend") Long id){ + friendService.requestFriend(authentication.getName(),id); + } + + @PostMapping("/accept") + @Operation(summary = "친구 수락 API") + public void acceptFriend(Authentication authentication, + @RequestParam(name="friend") Long id){ + friendService.acceptFriend(authentication.getName(),id); } + + @PostMapping("/reject") + @Operation(summary = "친구 거절 API") + public void rejectFriend(Authentication authentication, + @RequestParam(name="friend") Long id){ + friendService.rejectFriend(authentication.getName(),id); + } + + @GetMapping("/request") + @Operation(summary = "친구 요청 조회 API", description ="수락 대기중인 요청만 나타낸다.") + public ResponseEntity> getRequestedFriends(Authentication authentication, + @RequestParam(value="page", defaultValue="0") int page){ + return ResponseEntity.status(HttpStatus.OK).body(friendService.getRequestedFriends(page, authentication.getName())); + } + + +} diff --git a/src/main/java/team/haedal/gifticionfunding/controller/FundingController.java b/src/main/java/team/haedal/gifticionfunding/controller/FundingController.java new file mode 100644 index 0000000..3dccf08 --- /dev/null +++ b/src/main/java/team/haedal/gifticionfunding/controller/FundingController.java @@ -0,0 +1,64 @@ +package team.haedal.gifticionfunding.controller; + +import io.swagger.v3.oas.annotations.Hidden; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.tags.Tag; +import lombok.RequiredArgsConstructor; +import org.springframework.http.HttpStatus; +import org.springframework.http.ResponseEntity; +import org.springframework.security.core.Authentication; +import org.springframework.web.bind.annotation.*; +import org.springframework.web.servlet.config.annotation.EnableWebMvc; +import team.haedal.gifticionfunding.dto.PageResponse; +import team.haedal.gifticionfunding.dto.request.FundingArticleRequest; +import team.haedal.gifticionfunding.dto.request.FundingJoinRequest; +import team.haedal.gifticionfunding.dto.response.FundingResponse; +import team.haedal.gifticionfunding.service.FundingService; + +@RestController +@RequiredArgsConstructor +@EnableWebMvc +@RequestMapping("/api/funding") +@Tag(name="Funding",description="펀딩 관련 API") +public class FundingController { + //TODO: 가능한 펀딩 조회, 참여한 펀딩 조회, 생성한 펀딩 조회 + //TODO: 펀딩 생성 (유효하지 않은 기프티콘이 하나라도 포함된다면 전체 fail) + private final FundingService fundingService; + + @GetMapping() + @Operation(summary = "가능한 펀딩 조회 API") + public ResponseEntity> getFundings(Authentication authentication, + @RequestParam(value="page", defaultValue="0") int page){ + return ResponseEntity.status(HttpStatus.OK).body(fundingService.getFundings(page, authentication.getName())); + } + + @GetMapping("/participate") + @Operation(summary = "참여한 펀딩 조회 API") + @Hidden + public ResponseEntity> getTakenFundings(Authentication authentication, + @RequestParam(value="page", defaultValue="0") int page){ + return ResponseEntity.status(HttpStatus.OK).body(fundingService.getTakenFundings(page, authentication.getName())); + } + + @GetMapping("/created") + @Operation(summary = "생성한 펀딩 조회 API") + public ResponseEntity> getCreatedFundgins(Authentication authentication, + @RequestParam(value="page", defaultValue="0") int page){ + return ResponseEntity.status(HttpStatus.OK).body(fundingService.getCreatedFundgins(page, authentication.getName())); + } + + @PostMapping() + @Operation(summary = "펀딩 생성 API") + public void createFunding(Authentication authentication, + @RequestBody FundingArticleRequest request){ + fundingService.createFunding(authentication.getName(), request); + } + + @PostMapping("/participate") + @Operation(summary = "펀딩 참여 API") + public void participateFunding(Authentication authentication, + @RequestBody FundingJoinRequest request){ + fundingService.participateFunding(authentication.getName(), request); + } + +} diff --git a/src/main/java/team/haedal/gifticionfunding/domain/Friendship.java b/src/main/java/team/haedal/gifticionfunding/domain/Friendship.java new file mode 100644 index 0000000..1c32da5 --- /dev/null +++ b/src/main/java/team/haedal/gifticionfunding/domain/Friendship.java @@ -0,0 +1,67 @@ +package team.haedal.gifticionfunding.domain; + +import jakarta.persistence.*; +import lombok.Builder; +import lombok.Getter; +import lombok.NoArgsConstructor; +import org.hibernate.annotations.OnDelete; +import org.hibernate.annotations.OnDeleteAction; +import team.haedal.gifticionfunding.domain.enums.FriendStatus; + +import java.time.LocalDateTime; + +@Entity +@Getter +@NoArgsConstructor +public class Friendship { + @Id + @GeneratedValue(strategy = GenerationType.IDENTITY) + private Long id; + + @ManyToOne(fetch = FetchType.LAZY) + @OnDelete(action = OnDeleteAction.CASCADE) + private Member member; + + @ManyToOne(fetch = FetchType.LAZY) + @OnDelete(action = OnDeleteAction.CASCADE) + private Member friend; + + private LocalDateTime createdAt; + + @Enumerated(EnumType.STRING) + private FriendStatus status; + + @Builder + private Friendship(Long id, Member member, Member friend, LocalDateTime createdAt, FriendStatus status) { + this.id = id; + this.member = member; + this.friend = friend; + this.createdAt = createdAt; + this.status = status; + } + + public static Friendship request(Member member, Member friend) { + return Friendship.builder() + .member(member) + .friend(friend) + .createdAt(LocalDateTime.now()) + .status(FriendStatus.WAITING) + .build(); + } + + public static Friendship finish(Member member, Member friend) { + return Friendship.builder() + .member(member) + .friend(friend) + .createdAt(LocalDateTime.now()) + .status(FriendStatus.ACCEPT) + .build(); + } + + public Friendship accept(){ + this.status = FriendStatus.ACCEPT; + return this; + } + + +} diff --git a/src/main/java/team/haedal/gifticionfunding/domain/Gifticon.java b/src/main/java/team/haedal/gifticionfunding/domain/Gifticon.java index 56860a0..a001acd 100644 --- a/src/main/java/team/haedal/gifticionfunding/domain/Gifticon.java +++ b/src/main/java/team/haedal/gifticionfunding/domain/Gifticon.java @@ -1,10 +1,7 @@ package team.haedal.gifticionfunding.domain; import jakarta.annotation.Nullable; -import jakarta.persistence.Entity; -import jakarta.persistence.GeneratedValue; -import jakarta.persistence.GenerationType; -import jakarta.persistence.Id; +import jakarta.persistence.*; import lombok.AllArgsConstructor; import lombok.Builder; import lombok.Getter; @@ -21,6 +18,7 @@ public class Gifticon { @Id @GeneratedValue(strategy = GenerationType.IDENTITY) + @Column(name = "gifticon_id") private Long id; private int price; private String name; diff --git a/src/main/java/team/haedal/gifticionfunding/domain/Member.java b/src/main/java/team/haedal/gifticionfunding/domain/Member.java index 861ef85..9a9b166 100644 --- a/src/main/java/team/haedal/gifticionfunding/domain/Member.java +++ b/src/main/java/team/haedal/gifticionfunding/domain/Member.java @@ -2,10 +2,7 @@ import jakarta.annotation.Nullable; import jakarta.persistence.*; -import lombok.AccessLevel; -import lombok.AllArgsConstructor; -import lombok.Builder; -import lombok.NoArgsConstructor; +import lombok.*; import team.haedal.gifticionfunding.domain.enums.Role; import java.time.LocalDate; @@ -14,6 +11,7 @@ @NoArgsConstructor(access = AccessLevel.PROTECTED) @AllArgsConstructor @Builder +@Getter public class Member { @Id @GeneratedValue(strategy = GenerationType.IDENTITY) diff --git a/src/main/java/team/haedal/gifticionfunding/domain/enums/FriendStatus.java b/src/main/java/team/haedal/gifticionfunding/domain/enums/FriendStatus.java new file mode 100644 index 0000000..81fc522 --- /dev/null +++ b/src/main/java/team/haedal/gifticionfunding/domain/enums/FriendStatus.java @@ -0,0 +1,5 @@ +package team.haedal.gifticionfunding.domain.enums; + +public enum FriendStatus { + ACCEPT, WAITING +} diff --git a/src/main/java/team/haedal/gifticionfunding/domain/funding/FundingArticle.java b/src/main/java/team/haedal/gifticionfunding/domain/funding/FundingArticle.java new file mode 100644 index 0000000..da9149a --- /dev/null +++ b/src/main/java/team/haedal/gifticionfunding/domain/funding/FundingArticle.java @@ -0,0 +1,67 @@ +package team.haedal.gifticionfunding.domain.funding; + +import jakarta.persistence.*; +import lombok.Builder; +import lombok.Getter; +import lombok.NoArgsConstructor; +import org.hibernate.annotations.OnDelete; +import org.hibernate.annotations.OnDeleteAction; +import team.haedal.gifticionfunding.domain.Gifticon; +import team.haedal.gifticionfunding.domain.Member; + +import java.time.LocalDate; +import java.time.LocalDateTime; +import java.util.ArrayList; +import java.util.List; + +@Entity +@Getter +@NoArgsConstructor +public class FundingArticle { + @Id + @GeneratedValue(strategy = GenerationType.IDENTITY) + @Column(name = "funding_id") + private Long id; + + @ManyToOne(fetch = FetchType.LAZY) + @OnDelete(action = OnDeleteAction.CASCADE) + private Member member; + + private LocalDateTime createdAt; + + private LocalDate endAt; + + private String title; + + @Column(length = 50000) + private String content; + + @ManyToMany(fetch = FetchType.LAZY) + @JoinTable(name = "funding_gifticon", + joinColumns = @JoinColumn(name = "funding_id"), + inverseJoinColumns = @JoinColumn(name = "gifticon_id")) + private List gifticonList = new ArrayList<>(); + + @Builder + private FundingArticle(Long id, Member member, LocalDateTime createdAt, LocalDate endAt, String title, String content, List gifticonList){ + this.id = id; + this.member = member; + this.createdAt = createdAt; + this.endAt = endAt; + this.title = title; + this.content = content; + this.gifticonList = gifticonList; + } + + + public static FundingArticle of(Member member, LocalDate endAt, String title, String content, List gifticonList){ + return FundingArticle.builder() + .member(member) + .createdAt(LocalDateTime.now()) + .endAt(endAt) + .title(title) + .content(content) + .gifticonList(gifticonList) + .build(); + } +} diff --git a/src/main/java/team/haedal/gifticionfunding/domain/funding/FundingContribute.java b/src/main/java/team/haedal/gifticionfunding/domain/funding/FundingContribute.java new file mode 100644 index 0000000..bab57a2 --- /dev/null +++ b/src/main/java/team/haedal/gifticionfunding/domain/funding/FundingContribute.java @@ -0,0 +1,58 @@ +package team.haedal.gifticionfunding.domain.funding; + +import jakarta.persistence.*; +import lombok.Builder; +import lombok.Getter; +import lombok.NoArgsConstructor; +import org.hibernate.annotations.OnDelete; +import org.hibernate.annotations.OnDeleteAction; +import team.haedal.gifticionfunding.domain.Member; +import team.haedal.gifticionfunding.domain.MemberGifticon; + +import java.time.LocalDateTime; + +@Entity +@Getter +@NoArgsConstructor +public class FundingContribute { + @Id + @GeneratedValue(strategy = GenerationType.IDENTITY) + private Long id; + + @ManyToOne(fetch = FetchType.LAZY) + @OnDelete(action = OnDeleteAction.CASCADE) + private Member participant; + + @ManyToOne(fetch = FetchType.LAZY) + @OnDelete(action = OnDeleteAction.CASCADE) + private FundingArticle fundingArticle; + + @ManyToOne(fetch = FetchType.LAZY) + @OnDelete(action = OnDeleteAction.CASCADE) + private MemberGifticon memberGifticon; + + private LocalDateTime createdAt; + + private int point; + + @Builder + private FundingContribute(Member participant, FundingArticle fundingArticle, MemberGifticon memberGifticon, LocalDateTime createdAt, int point){ + this.participant = participant; + this.fundingArticle = fundingArticle; + this.memberGifticon = memberGifticon; + this.createdAt = createdAt; + this.point = point; + } + + public static FundingContribute of(Member participant, FundingArticle fundingArticle, MemberGifticon memberGifticon, int point){ + return FundingContribute.builder() + .participant(participant) + .fundingArticle(fundingArticle) + .memberGifticon(memberGifticon) + .createdAt(LocalDateTime.now()) + .point(point) + .build(); + } + + +} diff --git a/src/main/java/team/haedal/gifticionfunding/domain/funding/FundingGifticon.java b/src/main/java/team/haedal/gifticionfunding/domain/funding/FundingGifticon.java new file mode 100644 index 0000000..1b71493 --- /dev/null +++ b/src/main/java/team/haedal/gifticionfunding/domain/funding/FundingGifticon.java @@ -0,0 +1,40 @@ +package team.haedal.gifticionfunding.domain.funding; + +import jakarta.persistence.*; +import lombok.Builder; +import lombok.NoArgsConstructor; +import org.hibernate.annotations.OnDelete; +import org.hibernate.annotations.OnDeleteAction; +import team.haedal.gifticionfunding.domain.Gifticon; + + +@Entity +@NoArgsConstructor +public class FundingGifticon { + @Id + @GeneratedValue(strategy = GenerationType.IDENTITY) + private Long id; + @ManyToOne() + @JoinColumn(name = "gifticon_id") + @OnDelete(action = OnDeleteAction.CASCADE) + private Gifticon gifticon; + @ManyToOne() + @OnDelete(action = OnDeleteAction.CASCADE) + @JoinColumn(name = "funding_article_id") + private FundingArticle fundingArticle; + private int point; + + @Builder + private FundingGifticon(FundingArticle fundingArticle, Gifticon gifticon) { + this.fundingArticle = fundingArticle; + this.gifticon = gifticon; + this.point = gifticon.getPrice(); + } + + public static FundingGifticon create(FundingArticle fundingArticle, Gifticon gifticon) { + return FundingGifticon.builder() + .fundingArticle(fundingArticle) + .gifticon(gifticon) + .build(); + } +} diff --git a/src/main/java/team/haedal/gifticionfunding/dto/PageResponse.java b/src/main/java/team/haedal/gifticionfunding/dto/PageResponse.java new file mode 100644 index 0000000..0814477 --- /dev/null +++ b/src/main/java/team/haedal/gifticionfunding/dto/PageResponse.java @@ -0,0 +1,30 @@ +package team.haedal.gifticionfunding.dto; + +import lombok.Builder; +import lombok.Getter; +import org.springframework.data.domain.Page; + +import java.util.List; + +@Getter +public class PageResponse { + private List content; + private int page; + private boolean isLast; + + @Builder + private PageResponse(List content, int page, boolean isLast){ + this.content = content; + this.page = page; + this.isLast = isLast; + } + + public static PageResponse from(Page data){ + return PageResponse.builder() + .content(data.getContent()) + .page(data.getNumber()) + .isLast(data.isLast()) + .build(); + } + +} diff --git a/src/main/java/team/haedal/gifticionfunding/dto/request/FundingArticleRequest.java b/src/main/java/team/haedal/gifticionfunding/dto/request/FundingArticleRequest.java new file mode 100644 index 0000000..30dfa42 --- /dev/null +++ b/src/main/java/team/haedal/gifticionfunding/dto/request/FundingArticleRequest.java @@ -0,0 +1,21 @@ +package team.haedal.gifticionfunding.dto.request; + +import lombok.Getter; + +import java.time.LocalDate; +import java.util.List; + +@Getter +public class FundingArticleRequest { + /** + * - 사용자는 펀딩을 생성할 수 있다. + * - 펀딩 게시글 생성시 제목, 내용이 포함된다. + * - 펀딩 시 2가지 금액대의 물건을 등록할 수 있다. + * - 2가지 금액대가 아니라 여러개 등록 가능하게 + * - 생일 14일전~ 당일 까지 펀딩 기간을 설정할 수 있다. + */ + private String title; + private String content; + private LocalDate endAt; + private List gifticonIdList; +} diff --git a/src/main/java/team/haedal/gifticionfunding/dto/request/FundingJoinRequest.java b/src/main/java/team/haedal/gifticionfunding/dto/request/FundingJoinRequest.java new file mode 100644 index 0000000..c6d5626 --- /dev/null +++ b/src/main/java/team/haedal/gifticionfunding/dto/request/FundingJoinRequest.java @@ -0,0 +1,9 @@ +package team.haedal.gifticionfunding.dto.request; + +import lombok.Getter; + +@Getter +public class FundingJoinRequest { + private Long articleId; + private Long memberGifticonId; +} diff --git a/src/main/java/team/haedal/gifticionfunding/dto/response/FundingResponse.java b/src/main/java/team/haedal/gifticionfunding/dto/response/FundingResponse.java new file mode 100644 index 0000000..a2c84b9 --- /dev/null +++ b/src/main/java/team/haedal/gifticionfunding/dto/response/FundingResponse.java @@ -0,0 +1,42 @@ +package team.haedal.gifticionfunding.dto.response; + +import lombok.Builder; +import lombok.Getter; +import team.haedal.gifticionfunding.domain.funding.FundingArticle; +import team.haedal.gifticionfunding.domain.Gifticon; + +import java.time.LocalDate; +import java.time.LocalDateTime; +import java.util.List; + +@Getter +public class FundingResponse { + private Long id; + private String title; + private String content; + private String createAt; + private String endAt; + private List gifticonList; + + @Builder + private FundingResponse(Long id, String title, String content, LocalDateTime createAt, LocalDate endAt, List gifticonList){ + this.id = id; + this.title = title; + this.content = content; + this.createAt = createAt.toString(); + this.endAt = endAt.toString(); + this.gifticonList = gifticonList; + } + + public static FundingResponse from(FundingArticle article){ + return FundingResponse.builder() + .id(article.getId()) + .title(article.getTitle()) + .content(article.getContent()) + .createAt(article.getCreatedAt()) + .endAt(article.getEndAt()) + .gifticonList(article.getGifticonList()) + .build(); + } + +} diff --git a/src/main/java/team/haedal/gifticionfunding/dto/response/friend/FriendResponse.java b/src/main/java/team/haedal/gifticionfunding/dto/response/friend/FriendResponse.java new file mode 100644 index 0000000..b8c8cbb --- /dev/null +++ b/src/main/java/team/haedal/gifticionfunding/dto/response/friend/FriendResponse.java @@ -0,0 +1,33 @@ +package team.haedal.gifticionfunding.dto.response.friend; + +import com.fasterxml.jackson.annotation.JsonAutoDetect; +import lombok.Builder; +import lombok.Getter; +import team.haedal.gifticionfunding.domain.Member; + +import java.time.LocalDate; + +@Getter +public class FriendResponse { + private Long id; + private String nickname; + private String profileImageUrl; + private LocalDate birthdate; + + @Builder + private FriendResponse(Long id, String nickname, String profileImageUrl, LocalDate birthdate){ + this.id = id; + this.nickname = nickname; + this.profileImageUrl = profileImageUrl; + this.birthdate = birthdate; + } + + public static FriendResponse from(Member member){ + return FriendResponse.builder() + .id(member.getId()) + .nickname(member.getNickname()) + .profileImageUrl(member.getProfileImageUrl()) + .birthdate(member.getBirthdate()) + .build(); + } +} diff --git a/src/main/java/team/haedal/gifticionfunding/exception/CustomException.java b/src/main/java/team/haedal/gifticionfunding/exception/CustomException.java index 61b5623..c22352b 100644 --- a/src/main/java/team/haedal/gifticionfunding/exception/CustomException.java +++ b/src/main/java/team/haedal/gifticionfunding/exception/CustomException.java @@ -13,4 +13,10 @@ public CustomException(ErrorCode errorCode) { this.errorCode = errorCode; this.message = errorCode.getMessage(); } + + public CustomException(ErrorCode errorCode, String message) { + this.result = errorCode.getStatus(); + this.errorCode = errorCode; + this.message = message; + } } diff --git a/src/main/java/team/haedal/gifticionfunding/exception/ErrorCode.java b/src/main/java/team/haedal/gifticionfunding/exception/ErrorCode.java index 82db847..7bec815 100644 --- a/src/main/java/team/haedal/gifticionfunding/exception/ErrorCode.java +++ b/src/main/java/team/haedal/gifticionfunding/exception/ErrorCode.java @@ -13,7 +13,8 @@ public enum ErrorCode { NOT_FOUND(404,HttpStatus.NOT_FOUND, "데이터를 찾을 수 없습니다"), INVALID_PERMISSION(401,HttpStatus.UNAUTHORIZED, "권한이 없습니다"), - INVALID_INPUT(400, HttpStatus.BAD_REQUEST,"잘못된 요청입니다."); + INVALID_INPUT(400, HttpStatus.BAD_REQUEST,"잘못된 요청입니다."), + USER_NOT_FOUND(400,HttpStatus.BAD_REQUEST,"사용자를 찾을 수 없습니다."); private int status; private HttpStatus error; private String message; diff --git a/src/main/java/team/haedal/gifticionfunding/exception/GlobalExceptionHandler.java b/src/main/java/team/haedal/gifticionfunding/exception/GlobalExceptionHandler.java index 49d2d50..13facd7 100644 --- a/src/main/java/team/haedal/gifticionfunding/exception/GlobalExceptionHandler.java +++ b/src/main/java/team/haedal/gifticionfunding/exception/GlobalExceptionHandler.java @@ -10,6 +10,6 @@ public ResponseEntity exceptionHandler(CustomException exception) { // exception.printStackTrace(); return ResponseEntity.status(exception.getErrorCode().getError()) - .body(new ExceptionDto(exception.getErrorCode())); + .body(new ExceptionDto(exception.getErrorCode(), exception.getMessage())); } } diff --git a/src/main/java/team/haedal/gifticionfunding/jwt/JwtProvider.java b/src/main/java/team/haedal/gifticionfunding/jwt/JwtProvider.java index f9d0f0d..03f75c5 100644 --- a/src/main/java/team/haedal/gifticionfunding/jwt/JwtProvider.java +++ b/src/main/java/team/haedal/gifticionfunding/jwt/JwtProvider.java @@ -12,7 +12,7 @@ public class JwtProvider { @Value("${jwt.secret}") private String secretKey; - private static final long ACCESS_TOKEN_EXPIRE_TIME = 1000 * 60 * 30; + private static final long ACCESS_TOKEN_EXPIRE_TIME = 1000 * 60 * 30000; private static final long REFRESH_TOKEN_EXPIRE_TIME = 1000 * 60 * 60 * 24 * 7; private String createAccessToken(String memberId){ diff --git a/src/main/java/team/haedal/gifticionfunding/repository/FriendRepository.java b/src/main/java/team/haedal/gifticionfunding/repository/FriendRepository.java new file mode 100644 index 0000000..16f07bc --- /dev/null +++ b/src/main/java/team/haedal/gifticionfunding/repository/FriendRepository.java @@ -0,0 +1,25 @@ +package team.haedal.gifticionfunding.repository; + +import org.springframework.data.domain.Page; +import org.springframework.data.domain.Pageable; +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 team.haedal.gifticionfunding.domain.Friendship; +import team.haedal.gifticionfunding.domain.Member; +import team.haedal.gifticionfunding.domain.enums.FriendStatus; +import team.haedal.gifticionfunding.repository.vo.FriendOnly; +import team.haedal.gifticionfunding.repository.vo.MemberOnly; + +import java.util.Optional; +public interface FriendRepository extends JpaRepository { + Page findAllByMemberAndStatus(Pageable pageable, Member member, FriendStatus status); + Page findAllByFriendAndStatus(Pageable pageable, Member friend, FriendStatus status); + + @Query(value = "select * from Friendship where member_id = :memberId and friend_id = :friendId", nativeQuery = true) + Optional findByMemberAndFriend(@Param("memberId") Long memberId, @Param("friendId") Long friendId); + + Optional findByMemberAndFriend(Member member, Member friend); + +} diff --git a/src/main/java/team/haedal/gifticionfunding/repository/FundingArticleRepository.java b/src/main/java/team/haedal/gifticionfunding/repository/FundingArticleRepository.java new file mode 100644 index 0000000..8896c68 --- /dev/null +++ b/src/main/java/team/haedal/gifticionfunding/repository/FundingArticleRepository.java @@ -0,0 +1,23 @@ +package team.haedal.gifticionfunding.repository; + +import org.springframework.data.domain.Page; +import org.springframework.data.domain.Pageable; +import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.data.jpa.repository.Query; +import org.springframework.data.repository.query.Param; +import team.haedal.gifticionfunding.domain.funding.FundingArticle; +import team.haedal.gifticionfunding.domain.Member; + +public interface FundingArticleRepository extends JpaRepository { + Page findByMember(Pageable pageable, Member member); + + @Query(value = "select * from funding_article where member_id in " + + "((select distinct b.friend_id " + + "from friendship a join friendship b " + + "where a.member_id = :memberId and b.friend_id != :memberId " + + "and a.friend_id=b.member_id) " + + "union " + + "(select a.friend_id " + + "from friendship a where a.member_id = :memberId))",nativeQuery = true) + Page findByFriendAndFriendOfFriend(Pageable pageable, @Param("memberId") Long memberId); +} diff --git a/src/main/java/team/haedal/gifticionfunding/repository/FundingContributeRepository.java b/src/main/java/team/haedal/gifticionfunding/repository/FundingContributeRepository.java new file mode 100644 index 0000000..a25403a --- /dev/null +++ b/src/main/java/team/haedal/gifticionfunding/repository/FundingContributeRepository.java @@ -0,0 +1,7 @@ +package team.haedal.gifticionfunding.repository; + +import org.springframework.data.jpa.repository.JpaRepository; +import team.haedal.gifticionfunding.domain.funding.FundingContribute; + +public interface FundingContributeRepository extends JpaRepository { +} diff --git a/src/main/java/team/haedal/gifticionfunding/repository/FundingGifticonRepository.java b/src/main/java/team/haedal/gifticionfunding/repository/FundingGifticonRepository.java new file mode 100644 index 0000000..4badbd4 --- /dev/null +++ b/src/main/java/team/haedal/gifticionfunding/repository/FundingGifticonRepository.java @@ -0,0 +1,7 @@ +package team.haedal.gifticionfunding.repository; + +import org.springframework.data.jpa.repository.JpaRepository; +import team.haedal.gifticionfunding.domain.funding.FundingGifticon; + +public interface FundingGifticonRepository extends JpaRepository { +} diff --git a/src/main/java/team/haedal/gifticionfunding/repository/GifticonRepository.java b/src/main/java/team/haedal/gifticionfunding/repository/GifticonRepository.java index 3f2bda3..74aa404 100644 --- a/src/main/java/team/haedal/gifticionfunding/repository/GifticonRepository.java +++ b/src/main/java/team/haedal/gifticionfunding/repository/GifticonRepository.java @@ -3,5 +3,8 @@ import org.springframework.data.jpa.repository.JpaRepository; import team.haedal.gifticionfunding.domain.Gifticon; +import java.util.List; + public interface GifticonRepository extends JpaRepository { + List findByIdIn(List id); } diff --git a/src/main/java/team/haedal/gifticionfunding/repository/MemberGifticonRepository.java b/src/main/java/team/haedal/gifticionfunding/repository/MemberGifticonRepository.java new file mode 100644 index 0000000..c2c5f6d --- /dev/null +++ b/src/main/java/team/haedal/gifticionfunding/repository/MemberGifticonRepository.java @@ -0,0 +1,7 @@ +package team.haedal.gifticionfunding.repository; + +import org.springframework.data.jpa.repository.JpaRepository; +import team.haedal.gifticionfunding.domain.MemberGifticon; + +public interface MemberGifticonRepository extends JpaRepository { +} diff --git a/src/main/java/team/haedal/gifticionfunding/repository/MemberRepository.java b/src/main/java/team/haedal/gifticionfunding/repository/MemberRepository.java index b9e339d..678cab7 100644 --- a/src/main/java/team/haedal/gifticionfunding/repository/MemberRepository.java +++ b/src/main/java/team/haedal/gifticionfunding/repository/MemberRepository.java @@ -2,9 +2,21 @@ import org.springframework.data.jpa.repository.JpaRepository; import team.haedal.gifticionfunding.domain.Member; +import team.haedal.gifticionfunding.exception.CustomException; +import team.haedal.gifticionfunding.exception.ErrorCode; import java.util.Optional; public interface MemberRepository extends JpaRepository { Optional findByNickname(String nickname); + + default Member getUserByName(String name) { + return this.findByNickname(name).orElseThrow( + () -> new CustomException(ErrorCode.USER_NOT_FOUND)); + } + + default Member getUserById(Long id) { + return this.findById(id).orElseThrow( + () -> new CustomException(ErrorCode.USER_NOT_FOUND)); + } } diff --git a/src/main/java/team/haedal/gifticionfunding/repository/vo/FriendOnly.java b/src/main/java/team/haedal/gifticionfunding/repository/vo/FriendOnly.java new file mode 100644 index 0000000..ccd3db3 --- /dev/null +++ b/src/main/java/team/haedal/gifticionfunding/repository/vo/FriendOnly.java @@ -0,0 +1,7 @@ +package team.haedal.gifticionfunding.repository.vo; + +import team.haedal.gifticionfunding.domain.Member; + +public interface FriendOnly { + Member getFriend(); +} diff --git a/src/main/java/team/haedal/gifticionfunding/repository/vo/MemberOnly.java b/src/main/java/team/haedal/gifticionfunding/repository/vo/MemberOnly.java new file mode 100644 index 0000000..67a3d94 --- /dev/null +++ b/src/main/java/team/haedal/gifticionfunding/repository/vo/MemberOnly.java @@ -0,0 +1,7 @@ +package team.haedal.gifticionfunding.repository.vo; + +import team.haedal.gifticionfunding.domain.Member; + +public interface MemberOnly { + Member getMember(); +} diff --git a/src/main/java/team/haedal/gifticionfunding/service/FriendService.java b/src/main/java/team/haedal/gifticionfunding/service/FriendService.java new file mode 100644 index 0000000..837d03c --- /dev/null +++ b/src/main/java/team/haedal/gifticionfunding/service/FriendService.java @@ -0,0 +1,90 @@ +package team.haedal.gifticionfunding.service; + +import lombok.RequiredArgsConstructor; +import org.springframework.data.domain.Page; +import org.springframework.data.domain.PageRequest; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; +import team.haedal.gifticionfunding.domain.Friendship; +import team.haedal.gifticionfunding.domain.Member; +import team.haedal.gifticionfunding.domain.enums.FriendStatus; +import team.haedal.gifticionfunding.dto.PageResponse; +import team.haedal.gifticionfunding.dto.response.friend.FriendResponse; +import team.haedal.gifticionfunding.exception.CustomException; +import team.haedal.gifticionfunding.exception.ErrorCode; +import team.haedal.gifticionfunding.repository.vo.FriendOnly; +import team.haedal.gifticionfunding.repository.FriendRepository; +import team.haedal.gifticionfunding.repository.vo.MemberOnly; +import team.haedal.gifticionfunding.repository.MemberRepository; + +import java.util.stream.Collectors; + + +@Service +@RequiredArgsConstructor +public class FriendService { + private final MemberRepository memberRepository; + private final FriendRepository friendRepository; + + + @Transactional(readOnly = true) + public PageResponse getFriends(int page, String name){ + Member member = memberRepository.getUserByName(name); + Page pageData = friendRepository.findAllByMemberAndStatus(PageRequest.of(page, 10), member, FriendStatus.ACCEPT); + + return PageResponse.builder() + .content(pageData.getContent().stream() + .map(data -> FriendResponse.from(data.getFriend())) + .collect(Collectors.toList())) + .page(pageData.getNumber()) + .isLast(pageData.isLast()) + .build(); + } + + + @Transactional() + public void requestFriend(String name, Long friendId){ + Member sender = memberRepository.getUserByName(name); + Member receiver = memberRepository.getUserById(friendId); + + friendRepository.save(Friendship.request(sender,receiver)); + } + + + @Transactional() + public void acceptFriend(String name, Long friendId){ + Member receiver = memberRepository.getUserByName(name); + Member sender = memberRepository.getUserById(friendId); + Friendship friendship = friendRepository.findByMemberAndFriend(sender, receiver) + .orElseThrow(() -> new CustomException(ErrorCode.USER_NOT_FOUND)); + friendship.accept(); + friendRepository.save(Friendship.finish(receiver,sender)); + } + + + @Transactional() + public void rejectFriend(String name, Long friendId){ + Member receiver = memberRepository.getUserByName(name); + Friendship friendship = friendRepository.findByMemberAndFriend(friendId, receiver.getId()) + .orElseThrow(() -> new CustomException(ErrorCode.USER_NOT_FOUND)); + + // friendship에 접근할때 sender를 조회하기 위한 쿼리가 한번 더 나감 (N+1) + friendRepository.delete(friendship); + } + + + @Transactional(readOnly = true) + public PageResponse getRequestedFriends(int page, String name){ + Member receiver = memberRepository.getUserByName(name); + Page pageData = friendRepository.findAllByFriendAndStatus(PageRequest.of(page, 10), receiver, FriendStatus.WAITING); + + return PageResponse.builder() + .content(pageData.getContent().stream() + .map(data -> FriendResponse.from(data.getMember())) + .collect(Collectors.toList())) + .page(pageData.getNumber()) + .isLast(pageData.isLast()) + .build(); + } + +} diff --git a/src/main/java/team/haedal/gifticionfunding/service/FundingService.java b/src/main/java/team/haedal/gifticionfunding/service/FundingService.java new file mode 100644 index 0000000..a515bfd --- /dev/null +++ b/src/main/java/team/haedal/gifticionfunding/service/FundingService.java @@ -0,0 +1,112 @@ +package team.haedal.gifticionfunding.service; + +import lombok.RequiredArgsConstructor; +import org.springframework.data.domain.Page; +import org.springframework.data.domain.PageRequest; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; +import team.haedal.gifticionfunding.domain.*; +import team.haedal.gifticionfunding.domain.funding.FundingArticle; +import team.haedal.gifticionfunding.dto.PageResponse; +import team.haedal.gifticionfunding.dto.request.FundingArticleRequest; +import team.haedal.gifticionfunding.dto.request.FundingJoinRequest; +import team.haedal.gifticionfunding.dto.response.FundingResponse; +import team.haedal.gifticionfunding.exception.CustomException; +import team.haedal.gifticionfunding.exception.ErrorCode; +import team.haedal.gifticionfunding.repository.*; + +import java.util.List; +import java.util.stream.Collectors; + +import static team.haedal.gifticionfunding.common.DateUtils.diff; + +@Service +@RequiredArgsConstructor +public class FundingService { + private final MemberRepository memberRepository; + private final FundingArticleRepository fundingArticleRepository; + private final GifticonRepository gifticonRepository; + private final FundingContributeRepository contributeRepository; + private final MemberGifticonRepository memberGifticonRepository; + private final FundingGifticonRepository fundingGifticonRepository; + + @Transactional(readOnly = true) + public PageResponse getFundings(int page, String name){ + /** + * funding article 의 작성자가 친구인 경우, 친구의 친구인 경우 조회 + */ + Member owner = memberRepository.getUserByName(name); + Page pageData = fundingArticleRepository.findByFriendAndFriendOfFriend(PageRequest.of(page, 10), owner.getId()); + + return PageResponse.builder() + .content(pageData.getContent().stream() + .map(FundingResponse::from) + .collect(Collectors.toList())) + .page(pageData.getNumber()) + .isLast(pageData.isLast()) + .build(); + } + + @Transactional(readOnly = true) + public PageResponse getTakenFundings(int page, String name){ + return null; + } + + public PageResponse getCreatedFundgins(int page, String name){ + Member owner = memberRepository.getUserByName(name); + Page pageData = fundingArticleRepository.findByMember(PageRequest.of(page, 10), owner); + + return PageResponse.builder() + .content(pageData.getContent().stream() + .map(FundingResponse::from) + .collect(Collectors.toList())) + .page(pageData.getNumber()) + .isLast(pageData.isLast()) + .build(); + } + + /** + * 1. member + * 2. 마감일이 유효한지 + * 3. 기프티콘이 유효한지(재고가 남아있어야 함) + */ + @Transactional + public void createFunding(String name, FundingArticleRequest request){ + Member member = memberRepository.getUserByName(name); + + long betweenDate = diff(request.getEndAt(),member.getBirthdate()); + if (betweenDate > 14 || betweenDate < 0) + throw new CustomException(ErrorCode.INVALID_INPUT, "잘못된 마감일입니다."); + + List gifticonList = gifticonRepository.findByIdIn(request.getGifticonIdList()); + gifticonList.forEach(gifticon -> { + if (gifticon.getStock() <= 0) + throw new CustomException(ErrorCode.INVALID_INPUT, "유효하지 않은 기프티콘이 있습니다."); + }); + fundingArticleRepository.save(FundingArticle.of(member, request.getEndAt().plusDays(1), + request.getTitle(), request.getContent(), + gifticonList)); + } + + + /** + * 게시자의 친구의 친구는 펀딩에 참여할 수 있다. + * 선택한 기프티콘이 게시자가 게시한 기프티콘 목록에 있다면 contribute를 한다. + * @param name + * @param request + */ + @Transactional + public void participateFunding(String name, FundingJoinRequest request){ + Member member = memberRepository.getUserByName(name); + FundingArticle fundingArticle = fundingArticleRepository.findById(request.getArticleId()) + .orElseThrow(() -> new CustomException(ErrorCode.INVALID_INPUT, "존재하지 않는 게시글입니다.")); + MemberGifticon gifticon = memberGifticonRepository.findById(request.getMemberGifticonId()) + .orElseThrow(() -> new CustomException(ErrorCode.INVALID_INPUT, "존재하지 않는 기프티콘입니다.")); + + if (!fundingArticle.getGifticonList().contains(request.getMemberGifticonId())){ + throw new CustomException(ErrorCode.INVALID_INPUT,"존재하지 않는 기프티콘입니다."); + } + + + } +} diff --git a/src/test/java/team/haedal/gifticionfunding/controller/FriendControllerTest.java b/src/test/java/team/haedal/gifticionfunding/controller/FriendControllerTest.java new file mode 100644 index 0000000..4702b62 --- /dev/null +++ b/src/test/java/team/haedal/gifticionfunding/controller/FriendControllerTest.java @@ -0,0 +1,67 @@ +package team.haedal.gifticionfunding.controller; + +import com.fasterxml.jackson.databind.ObjectMapper; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc; +import org.springframework.boot.test.autoconfigure.web.servlet.WebMvcTest; +import org.springframework.boot.test.mock.mockito.MockBean; +import org.springframework.http.MediaType; +import org.springframework.test.web.servlet.MockMvc; +import org.springframework.test.web.servlet.request.MockMvcRequestBuilders; +import team.haedal.gifticionfunding.dto.response.GifticonResponse; +import team.haedal.gifticionfunding.service.FriendService; +import team.haedal.gifticionfunding.service.GifticonServiceImpl; + +import java.util.ArrayList; +import java.util.List; + +import static org.junit.jupiter.api.Assertions.*; +import static org.mockito.BDDMockito.given; +import static org.springframework.security.test.web.servlet.request.SecurityMockMvcRequestPostProcessors.oauth2Login; +import static org.springframework.test.web.servlet.result.MockMvcResultHandlers.print; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; + +@WebMvcTest(FriendController.class) +@AutoConfigureMockMvc +class FriendControllerTest { + @Autowired + private MockMvc mockMvc; + + @MockBean + FriendService friendService; + + @Autowired + ObjectMapper objectMapper; + + //TODO: Test: 승인된 친구만 조회되는지(승인된 친구가 요청목록에 없어지는지), 친구 중복 요청안되는지 + //TODO: Test: 만약에 두명이 서로 친구 요청을 보내고 하나의 요청이 승인되면 -> 둘은 친구임 -> 근데 waiting인게 디비에 영원히 남아있음 + //TODO: Test: 친구가 서로 동시에 요청을 보낸다면? + + @Test + @DisplayName("친구목록 조회 테스트") + void getFriends() { + + } + + @Test + @DisplayName("친구 요청 테스트") + void requestFriend() { + } + + @Test + @DisplayName("친구 수락 테스트") + void acceptFriend() { + } + + @Test + @DisplayName("친구 거절 테스트") + void rejectFriend() { + } + + @Test + @DisplayName("요청된 친구 목록 조회 테스트") + void getRequestedFriends() { + } +} \ No newline at end of file diff --git a/src/test/java/team/haedal/gifticionfunding/controller/GifticonControllerTest.java b/src/test/java/team/haedal/gifticionfunding/controller/GifticonControllerTest.java index 99dd5ed..a719f93 100644 --- a/src/test/java/team/haedal/gifticionfunding/controller/GifticonControllerTest.java +++ b/src/test/java/team/haedal/gifticionfunding/controller/GifticonControllerTest.java @@ -19,13 +19,13 @@ import java.util.List; import static org.mockito.BDDMockito.given; +import static org.mockito.Mockito.verify; import static org.springframework.security.test.web.servlet.request.SecurityMockMvcRequestPostProcessors.oauth2Login; import static org.springframework.test.web.servlet.result.MockMvcResultHandlers.print; import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.jsonPath; import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; @WebMvcTest(GifticonController.class) -@AutoConfigureMockMvc public class GifticonControllerTest { @Autowired private MockMvc mockMvc; @@ -82,5 +82,8 @@ void getGifticonDetail() throws Exception { .andExpect(jsonPath("$.expirationDate").exists()) .andDo(print()); + // verify : 메소드가 실행이 됐는지를 확인 + verify(gifticonService).getGifticonDetail(1L); + } } diff --git a/src/test/java/team/haedal/gifticionfunding/service/FriendServiceTest.java b/src/test/java/team/haedal/gifticionfunding/service/FriendServiceTest.java new file mode 100644 index 0000000..cdd101d --- /dev/null +++ b/src/test/java/team/haedal/gifticionfunding/service/FriendServiceTest.java @@ -0,0 +1,123 @@ +package team.haedal.gifticionfunding.service; + +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.springframework.test.context.junit.jupiter.SpringExtension; +import team.haedal.gifticionfunding.domain.Friendship; +import team.haedal.gifticionfunding.domain.Member; +import team.haedal.gifticionfunding.domain.enums.FriendStatus; +import team.haedal.gifticionfunding.domain.enums.Role; +import team.haedal.gifticionfunding.repository.FriendRepository; +import team.haedal.gifticionfunding.repository.MemberRepository; + +import java.time.LocalDate; +import java.time.LocalDateTime; +import java.util.Optional; + + +import static org.mockito.ArgumentMatchers.*; +import static org.mockito.Mockito.verify; + +@ExtendWith(SpringExtension.class) +public class FriendServiceTest { + @Mock + private MemberRepository memberRepository; + @Mock + private FriendRepository friendRepository; + @InjectMocks + private FriendService friendService; + + @Override + public boolean equals(Object o){ + Friendship friendship = (Friendship) o; + return true; + } + + + + //TODO: Test: 승인된 친구만 조회되는지(승인된 친구가 요청목록에 없어지는지), 친구 중복 요청안되는지 + //TODO: Test: 만약에 두명이 서로 친구 요청을 보내고 하나의 요청이 승인되면 -> 둘은 친구임 -> 근데 waiting인게 디비에 영원히 남아있음 + //TODO: Test: 친구가 서로 동시에 요청을 보낸다면? + + @Test + void requestFriend() { + String[] attrs = toArray("좋은","빠른"); + } + + static T[] pickTwo(T a, T b) { + System.out.println("pickTwo: "+a.getClass()); + return toArray(a, b); + } + static T[] toArray(T... args){ + System.out.println("toArray: "+args.getClass()); + return args; + } + + + + @Test + void getRequestedFriends() { + //given + Member member = createMember("사용자"); + Member friend1 = createMember("친구"); + Mockito.when(memberRepository.getUserByName(member.getNickname())).thenReturn(member); + Mockito.when(memberRepository.findById(friend1.getId())).thenReturn(Optional.of(friend1)); + + //given + Friendship friendship = createFriendRequest(friend1,member); + + friendService.requestFriend(member.getNickname(),friend1.getId()); + + verify(friendRepository).save(any(Friendship.class)); + } + + @Test + void acceptFriend() { + } + + @Test + @DisplayName("사용자와 친구관계인 member를 조회한다.") + void getFriends() { + //given + + + + + //when + + } + + + @Test + void rejectFriend() { + } + + + Member createMember(String name){ + return Member.builder() + .email("email@email.com") + .nickname(name) + .point(0L) + .birthdate(LocalDate.of(2001,9,15)) + .profileImageUrl("http://profile.png") + .role(Role.MEMBER) + .build(); + } + + Friendship createFriendRequest(Member to, Member from){ + return Friendship.builder() + .createdAt(LocalDateTime.now()) + .member(from) + .friend(to) + .status(FriendStatus.WAITING) + .build(); + } + + + + +}