-
Notifications
You must be signed in to change notification settings - Fork 3
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
[BE] feat: Club 생성 참여 탈퇴 API #207
Changes from all commits
7f84fb3
5be9f38
7dcafe2
188e30c
810324d
d6ee853
e698a87
3b417bd
46b4004
c6d25fa
4062cac
77a875d
f3174f2
66bc633
dd59fad
2041545
0beccdd
6ef0f9e
9262bcf
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change | ||||
---|---|---|---|---|---|---|
|
@@ -3,7 +3,9 @@ | |||||
import com.woowacourse.friendogly.exception.FriendoglyException; | ||||||
import com.woowacourse.friendogly.member.domain.Member; | ||||||
import com.woowacourse.friendogly.pet.domain.Gender; | ||||||
import com.woowacourse.friendogly.pet.domain.Pet; | ||||||
import com.woowacourse.friendogly.pet.domain.SizeType; | ||||||
import jakarta.persistence.CascadeType; | ||||||
import jakarta.persistence.CollectionTable; | ||||||
import jakarta.persistence.Column; | ||||||
import jakarta.persistence.ElementCollection; | ||||||
|
@@ -17,7 +19,11 @@ | |||||
import jakarta.persistence.Id; | ||||||
import jakarta.persistence.JoinColumn; | ||||||
import jakarta.persistence.ManyToOne; | ||||||
import jakarta.persistence.OneToMany; | ||||||
import java.time.LocalDateTime; | ||||||
import java.util.ArrayList; | ||||||
import java.util.List; | ||||||
import java.util.Objects; | ||||||
import java.util.Set; | ||||||
import lombok.AccessLevel; | ||||||
import lombok.Builder; | ||||||
|
@@ -71,8 +77,14 @@ public class Club { | |||||
@Column(name = "status", nullable = false) | ||||||
private Status status; | ||||||
|
||||||
@OneToMany(mappedBy = "club", orphanRemoval = true, cascade = CascadeType.ALL) | ||||||
List<ClubMember> clubMembers = new ArrayList<>(); | ||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 클럽이랑 생명주기가 완전 같으니까 oneToMany적용해서 cascade할 수 있는게 장점이네요~! |
||||||
|
||||||
@OneToMany(mappedBy = "club", orphanRemoval = true, cascade = CascadeType.ALL) | ||||||
List<ClubPet> clubPets = new ArrayList<>(); | ||||||
|
||||||
@Builder | ||||||
public Club( | ||||||
private Club( | ||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 굿 |
||||||
String title, | ||||||
String content, | ||||||
String address, | ||||||
|
@@ -97,7 +109,6 @@ public Club( | |||||
this.createdAt = createdAt; | ||||||
} | ||||||
|
||||||
|
||||||
private void validateOwner(Member owner) { | ||||||
if (owner == null) { | ||||||
throw new FriendoglyException("모임 방장 정보는 필수 입니다."); | ||||||
|
@@ -112,9 +123,10 @@ public static Club create( | |||||
Member owner, | ||||||
Set<Gender> allowedGender, | ||||||
Set<SizeType> allowedSize, | ||||||
String imageUrl | ||||||
String imageUrl, | ||||||
List<Pet> participatingPets | ||||||
) { | ||||||
return Club.builder() | ||||||
Club club = Club.builder() | ||||||
.title(title) | ||||||
.content(content) | ||||||
.address(address) | ||||||
|
@@ -126,6 +138,84 @@ public static Club create( | |||||
.createdAt(LocalDateTime.now()) | ||||||
.imageUrl(imageUrl) | ||||||
.build(); | ||||||
club.addClubMember(club.owner); | ||||||
club.addClubPet(participatingPets); | ||||||
return club; | ||||||
} | ||||||
|
||||||
public void addClubMember(Member newMember) { | ||||||
validateAlreadyExists(newMember); | ||||||
validateMemberCapacity(); | ||||||
ClubMember clubMember = ClubMember.create(this, newMember); | ||||||
clubMembers.add(clubMember); | ||||||
clubMember.updateClub(this); | ||||||
} | ||||||
Comment on lines
+146
to
+152
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
이쪽도 마찬가지 입니다. 변환 로직을 ClubMember로 넣어주면 책임을 나눌 수 있을 것 같습니다. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 엔티티에 동등성을 아직 부여하고 있지 않아서 contains 함수를 사용하는건 별개의 문제인 것 같아용 |
||||||
|
||||||
private void validateAlreadyExists(Member newMember) { | ||||||
if (clubMembers.stream() | ||||||
.anyMatch(clubMember -> Objects.equals(clubMember.getMember().getId(), newMember.getId())) | ||||||
) { | ||||||
throw new FriendoglyException("이미 참여 중인 모임입니다."); | ||||||
} | ||||||
} | ||||||
|
||||||
private void validateMemberCapacity() { | ||||||
if (memberCapacity.isCapacityReached(countClubMember())) { | ||||||
throw new FriendoglyException("최대 인원을 초과하여 모임에 참여할 수 없습니다."); | ||||||
} | ||||||
} | ||||||
|
||||||
public void addClubPet(List<Pet> pets) { | ||||||
List<ClubPet> clubPets = pets.stream() | ||||||
.peek(this::validateParticipatePet) | ||||||
.map(pet -> new ClubPet(this, pet)) | ||||||
.peek(clubPet -> clubPet.updateClub(this)) | ||||||
.toList(); | ||||||
this.clubPets.addAll(clubPets); | ||||||
} | ||||||
|
||||||
private void validateParticipatePet(Pet pet) { | ||||||
if (!allowedGenders.contains(pet.getGender()) || !allowedSizes.contains(pet.getSizeType())) { | ||||||
throw new FriendoglyException("모임에 데려갈 수 없는 강아지가 있습니다."); | ||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 이거는 데려갈 수 있는 강아지가 있는데, 없는 강아지도 포함되어있어서 그런거 아냐? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 지금 보니깐 , 모임에 데려갈 수 없는 강아지가 요청에 포함되어 있을 경우라서 저게 맞는 것 같아요. |
||||||
} | ||||||
} | ||||||
|
||||||
public int countClubMember() { | ||||||
return clubMembers.size(); | ||||||
} | ||||||
|
||||||
public boolean isEmpty() { | ||||||
return clubMembers.isEmpty(); | ||||||
} | ||||||
|
||||||
public void removeClubMember(Member member) { | ||||||
ClubMember target = clubMembers.stream() | ||||||
.filter(e -> e.getMember().getId().equals(member.getId())) | ||||||
.findAny() | ||||||
.orElseThrow(() -> new FriendoglyException("참여 중인 모임이 아닙니다.")); | ||||||
Comment on lines
+191
to
+195
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. public void removeClubMember(ClubMember clubMember) {
if (!clubMembers.remove(clubMember)) {
throw new FriendoglyException("참여 중인 모임이 아닙니다.");
}
// ...
} ClubMember를 인자로 받으면 로직을 더 간결하게 표현할 수 있겠습니다. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 엔티티에 동등성 부여하는게 가능하다면 저렇게 깔끔하게 해결할 수 있을 것 같아요. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 나는 id에만 동등성 부여하는 것 동의합니다.
1번은 id값이 다르기에 충분히 다른 사람이지만, 그렇기 때문에 id에만 동등성에 부여하는 것을 동의합니다! |
||||||
clubMembers.remove(target); | ||||||
if (isOwner(target)) { | ||||||
updateOwner(); | ||||||
Comment on lines
+197
to
+198
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 여기 가독성 훨씬 나아졌네요 |
||||||
} | ||||||
target.updateClub(null); | ||||||
removeClubPets(member); | ||||||
} | ||||||
|
||||||
private void updateOwner() { | ||||||
if (!isEmpty()) { | ||||||
this.owner = clubMembers.get(0).getMember(); | ||||||
} | ||||||
} | ||||||
|
||||||
private boolean isOwner(ClubMember target) { | ||||||
return owner.getId().equals(target.getMember().getId()); | ||||||
} | ||||||
|
||||||
private void removeClubPets(Member member) { | ||||||
List<ClubPet> participatingMemberPets = clubPets.stream() | ||||||
.filter(clubPet -> clubPet.getPet().getMember().getId().equals(member.getId())) | ||||||
.toList(); | ||||||
clubPets.removeAll(participatingMemberPets); | ||||||
participatingMemberPets.forEach(clubPet -> clubPet.updateClub(null)); | ||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 나중에 다같이 모여서 함께 얘기해봐요. |
||||||
} | ||||||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -2,13 +2,15 @@ | |
|
||
import com.woowacourse.friendogly.exception.FriendoglyException; | ||
import com.woowacourse.friendogly.member.domain.Member; | ||
import jakarta.persistence.Column; | ||
import jakarta.persistence.Entity; | ||
import jakarta.persistence.FetchType; | ||
import jakarta.persistence.GeneratedValue; | ||
import jakarta.persistence.GenerationType; | ||
import jakarta.persistence.Id; | ||
import jakarta.persistence.JoinColumn; | ||
import jakarta.persistence.ManyToOne; | ||
import java.time.LocalDateTime; | ||
import lombok.AccessLevel; | ||
import lombok.Builder; | ||
import lombok.Getter; | ||
|
@@ -31,12 +33,25 @@ public class ClubMember { | |
@JoinColumn(name = "member_id", nullable = false) | ||
private Member member; | ||
|
||
@Column(name = "create_at", nullable = false) | ||
private LocalDateTime createdAt; | ||
|
||
@Builder | ||
public ClubMember(Club club, Member member) { | ||
public ClubMember(Club club, Member member, LocalDateTime createdAt) { | ||
validateClub(club); | ||
validateMember(member); | ||
validateCreateAt(createdAt); | ||
this.club = club; | ||
this.member = member; | ||
this.createdAt = createdAt; | ||
} | ||
|
||
public static ClubMember create(Club club, Member member) { | ||
return ClubMember.builder() | ||
.club(club) | ||
.member(member) | ||
.createdAt(LocalDateTime.now()) | ||
.build(); | ||
} | ||
Comment on lines
+49
to
55
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 정적 팩토리를 사용할 거라면 생성자를 private으로 막으면 어떨까요? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 전 정적 팩토리 메서드 제거해도 괜찮을 것 같아요. |
||
|
||
private void validateClub(Club club) { | ||
|
@@ -45,9 +60,19 @@ private void validateClub(Club club) { | |
} | ||
} | ||
|
||
private void validateCreateAt(LocalDateTime createdAt) { | ||
if (createdAt == null) { | ||
throw new FriendoglyException("방에 참가한 시간은 필수입니다."); | ||
} | ||
} | ||
|
||
private void validateMember(Member member) { | ||
if (member == null) { | ||
throw new FriendoglyException("모임에 참여하는 회원 정보는 필수입니다."); | ||
} | ||
} | ||
|
||
public void updateClub(Club club) { | ||
this.club = club; | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,11 @@ | ||
package com.woowacourse.friendogly.club.dto.request; | ||
|
||
import jakarta.validation.constraints.NotEmpty; | ||
import java.util.List; | ||
|
||
public record SaveClubMemberRequest( | ||
@NotEmpty(message = "모임에 참석 할 강아지를 1마리 이상 선택해주세요.") | ||
List<Long> participatingPetsId | ||
) { | ||
|
||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,42 @@ | ||
package com.woowacourse.friendogly.club.dto.request; | ||
|
||
import com.woowacourse.friendogly.pet.domain.Gender; | ||
import com.woowacourse.friendogly.pet.domain.SizeType; | ||
import jakarta.validation.constraints.Max; | ||
import jakarta.validation.constraints.Min; | ||
import jakarta.validation.constraints.NotBlank; | ||
import jakarta.validation.constraints.NotEmpty; | ||
import jakarta.validation.constraints.Size; | ||
import java.util.List; | ||
import java.util.Set; | ||
|
||
public record SaveClubRequest( | ||
@NotBlank(message = "제목을 작성해주세요.") | ||
@Size(min = 1, max = 100, message = "제목은 1글자 100글자 사이입니다.") | ||
String title, | ||
|
||
@NotBlank(message = "본문을 작성해주세요.") | ||
@Size(min = 1, max = 1000, message = "본문은 1글자 1000글자 사이입니다.") | ||
String content, | ||
|
||
@NotBlank(message = "모임 사진을 등록해주세요.") | ||
String imageUrl, | ||
|
||
@NotBlank(message = "주소를 읽을 수 없습니다. 다시 시도해주세요.") | ||
String address, | ||
|
||
@NotEmpty(message = "모임에 참여가능한 성별을 선택해주세요.") | ||
Set<Gender> allowedGenders, | ||
|
||
@NotEmpty(message = "모임에 참여가능한 댕댕이 사이즈를 선택해주세요.") | ||
Set<SizeType> allowedSizes, | ||
|
||
@Min(value = 1, message = "모임 최대 인원은 1명 이상입니다.") | ||
@Max(value = 5, message = "모임 최대 인원은 5명 이하입니다.") | ||
int memberCapacity, | ||
|
||
@NotEmpty(message = "모임에 참여할 댕댕이를 선택해주세요.") | ||
List<Long> participatingPetsId | ||
) { | ||
|
||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
👍