diff --git a/src/main/java/likelion/MZConnent/api/club/ClubController.java b/src/main/java/likelion/MZConnent/api/club/ClubController.java index 4900a97..5920c2a 100644 --- a/src/main/java/likelion/MZConnent/api/club/ClubController.java +++ b/src/main/java/likelion/MZConnent/api/club/ClubController.java @@ -1,5 +1,6 @@ package likelion.MZConnent.api.club; +import jakarta.transaction.Transactional; import jakarta.validation.Valid; import likelion.MZConnent.domain.member.Member; import likelion.MZConnent.dto.club.request.ClubSimpleRequest; @@ -20,7 +21,6 @@ import org.springframework.validation.BindingResult; import org.springframework.web.bind.annotation.*; -import java.util.List; import java.util.Map; @Slf4j diff --git a/src/main/java/likelion/MZConnent/api/club/MyClubController.java b/src/main/java/likelion/MZConnent/api/club/MyClubController.java index d93d926..5d05380 100644 --- a/src/main/java/likelion/MZConnent/api/club/MyClubController.java +++ b/src/main/java/likelion/MZConnent/api/club/MyClubController.java @@ -1,23 +1,25 @@ package likelion.MZConnent.api.club; +import likelion.MZConnent.dto.club.request.EvaluateMemberRequest; +import likelion.MZConnent.dto.club.response.EvaluateMemberResponse; +import likelion.MZConnent.dto.club.response.MemberRateResponse; import likelion.MZConnent.dto.club.response.MyClubDetailResponse; import likelion.MZConnent.dto.club.response.MyClubSimpleResponse; import likelion.MZConnent.jwt.principle.UserPrinciple; import likelion.MZConnent.service.club.MyClubService; +import likelion.MZConnent.service.club.RateService; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; import org.springframework.http.ResponseEntity; import org.springframework.security.core.annotation.AuthenticationPrincipal; -import org.springframework.web.bind.annotation.GetMapping; -import org.springframework.web.bind.annotation.PathVariable; -import org.springframework.web.bind.annotation.RequestParam; -import org.springframework.web.bind.annotation.RestController; +import org.springframework.web.bind.annotation.*; @Slf4j @RequiredArgsConstructor @RestController public class MyClubController { private final MyClubService myClubService; + private final RateService rateService; @GetMapping("/api/users/clubs") public ResponseEntity getMyClubs(@AuthenticationPrincipal UserPrinciple userPrinciple) { @@ -32,4 +34,16 @@ public ResponseEntity getMyClubDetail(@AuthenticationPrinc } + @PostMapping("/api/clubs/{clubId}/members/{evaluateeId}/rate") + public ResponseEntity evaluateMember(@AuthenticationPrincipal UserPrinciple userPrinciple, @PathVariable Long clubId, @PathVariable Long evaluateeId, @RequestBody EvaluateMemberRequest request) { + EvaluateMemberResponse response = rateService.evaluateMember(userPrinciple.getEmail(), clubId, evaluateeId, request); + return ResponseEntity.ok(response); + } + + @GetMapping("/api/clubs/{clubId}/members/{evaluateeId}/rate/count") + public ResponseEntity getMemberRateAndCount(@AuthenticationPrincipal UserPrinciple userPrinciple, @PathVariable Long clubId, @PathVariable Long evaluateeId) { + MemberRateResponse response = rateService.getMemberRateCountAndCount(userPrinciple.getEmail(), clubId, evaluateeId); + return ResponseEntity.ok(response); + } + } diff --git a/src/main/java/likelion/MZConnent/dto/club/request/EvaluateMemberRequest.java b/src/main/java/likelion/MZConnent/dto/club/request/EvaluateMemberRequest.java new file mode 100644 index 0000000..00bdc0a --- /dev/null +++ b/src/main/java/likelion/MZConnent/dto/club/request/EvaluateMemberRequest.java @@ -0,0 +1,14 @@ +package likelion.MZConnent.dto.club.request; + +import lombok.Getter; +import lombok.NoArgsConstructor; + +@Getter +@NoArgsConstructor +public class EvaluateMemberRequest { + private int score; + + public EvaluateMemberRequest(int score) { + this.score = score; + } +} diff --git a/src/main/java/likelion/MZConnent/dto/club/response/EvaluateMemberResponse.java b/src/main/java/likelion/MZConnent/dto/club/response/EvaluateMemberResponse.java new file mode 100644 index 0000000..1b94f1d --- /dev/null +++ b/src/main/java/likelion/MZConnent/dto/club/response/EvaluateMemberResponse.java @@ -0,0 +1,14 @@ +package likelion.MZConnent.dto.club.response; + +import lombok.Getter; +import lombok.NoArgsConstructor; + +@Getter +@NoArgsConstructor +public class EvaluateMemberResponse { + private int rateCount; + + public EvaluateMemberResponse(int rateCount) { + this.rateCount = rateCount; + } +} diff --git a/src/main/java/likelion/MZConnent/dto/club/response/MemberRateResponse.java b/src/main/java/likelion/MZConnent/dto/club/response/MemberRateResponse.java new file mode 100644 index 0000000..a400181 --- /dev/null +++ b/src/main/java/likelion/MZConnent/dto/club/response/MemberRateResponse.java @@ -0,0 +1,24 @@ +package likelion.MZConnent.dto.club.response; + +import lombok.Builder; +import lombok.Getter; +import lombok.NoArgsConstructor; + +import java.math.BigDecimal; + +@Getter +@NoArgsConstructor +public class MemberRateResponse { + private int rateCount; + private String userName; + private BigDecimal averageMannersScore; + private String profileImageUrl; + + @Builder + public MemberRateResponse(int rateCount, String userName, BigDecimal averageMannersScore, String profileImageUrl) { + this.rateCount = rateCount; + this.userName = userName; + this.averageMannersScore = averageMannersScore; + this.profileImageUrl = profileImageUrl; + } +} diff --git a/src/main/java/likelion/MZConnent/repository/manner/MannerRepository.java b/src/main/java/likelion/MZConnent/repository/manner/MannerRepository.java index 6afb9bd..29a4a3e 100644 --- a/src/main/java/likelion/MZConnent/repository/manner/MannerRepository.java +++ b/src/main/java/likelion/MZConnent/repository/manner/MannerRepository.java @@ -1,9 +1,15 @@ package likelion.MZConnent.repository.manner; +import likelion.MZConnent.domain.club.ClubMember; import likelion.MZConnent.domain.manner.Manner; +import likelion.MZConnent.domain.member.Member; import org.springframework.data.jpa.repository.JpaRepository; import org.springframework.stereotype.Repository; +import java.util.List; + @Repository public interface MannerRepository extends JpaRepository { + long countByMemberAndClubMember(Member member, ClubMember clubMember); + List findByMember(Member member); } diff --git a/src/main/java/likelion/MZConnent/service/club/ClubService.java b/src/main/java/likelion/MZConnent/service/club/ClubService.java index 131f899..12a1ebe 100644 --- a/src/main/java/likelion/MZConnent/service/club/ClubService.java +++ b/src/main/java/likelion/MZConnent/service/club/ClubService.java @@ -111,13 +111,17 @@ private void validateJoinClub(Club club, Member member) { throw new IllegalArgumentException("정원이 초과되어 가입할 수 없습니다."); } - if (club.getAgeRestriction() != AgeRestriction.ALL && !(club.getAgeRestriction().equals(member.getAge()))) { + if (!club.getAgeRestriction().equals(AgeRestriction.ALL) && !club.getAgeRestriction().getAgeRestriction().equals(member.getAge().getName())) { throw new IllegalArgumentException("나이 제한으로 가입할 수 없습니다."); } - if (club.getGenderRestriction() != GenderRestriction.ALL && !(club.getGenderRestriction().equals(member.getGender()))) { + if (!club.getGenderRestriction().equals(GenderRestriction.ALL) && !club.getGenderRestriction().equals(member.getGender())) { throw new IllegalArgumentException("성별 제한으로 가입할 수 없습니다."); } + + if (club.getStatus().equals("CLOSE")) { + throw new IllegalArgumentException("모임이 마감되어 가입할 수 없습니다."); + } } @Scheduled(cron = "0 0 0 * * *", zone = "Asia/Seoul") diff --git a/src/main/java/likelion/MZConnent/service/club/RateService.java b/src/main/java/likelion/MZConnent/service/club/RateService.java new file mode 100644 index 0000000..8df3e88 --- /dev/null +++ b/src/main/java/likelion/MZConnent/service/club/RateService.java @@ -0,0 +1,130 @@ +package likelion.MZConnent.service.club; + +import jakarta.transaction.Transactional; +import likelion.MZConnent.domain.club.Club; +import likelion.MZConnent.domain.club.ClubMember; +import likelion.MZConnent.domain.manner.Manner; +import likelion.MZConnent.domain.member.Member; +import likelion.MZConnent.dto.club.request.EvaluateMemberRequest; +import likelion.MZConnent.dto.club.response.EvaluateMemberResponse; +import likelion.MZConnent.dto.club.response.MemberRateResponse; +import likelion.MZConnent.repository.club.ClubRepository; +import likelion.MZConnent.repository.manner.MannerRepository; +import likelion.MZConnent.repository.member.MemberRepository; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.springframework.stereotype.Service; + +import java.math.BigDecimal; +import java.util.List; + +@Service +@Slf4j +@RequiredArgsConstructor +@Transactional +public class RateService { + private final MemberRepository memberRepository; + private final ClubRepository clubRepository; + private final MannerRepository mannerRepository; + + public EvaluateMemberResponse evaluateMember(String email, Long clubId, Long evaluateeId, EvaluateMemberRequest request) { + Member member = getMemberByEmail(email); + Member evaluatee = getMemberById(evaluateeId); + Club club = getClubById(clubId); + + // 해당 유저들이 해당 모임에 가입되어 있는지 확인 + validateClubMember(club, member, evaluatee); + ClubMember memberClubMember = getClubMember(club, member); + + // 평가자가 해당 멤버에게 평가한 횟수 조회 + // 평가자가 해당 멤버의 평가를 2번 이상한 경우 예외 처리 + long evaluationCount = mannerRepository.countByMemberAndClubMember(evaluatee, memberClubMember); + if (evaluationCount >= 2) { + throw new IllegalArgumentException("해당 멤버에게 2번 이상 평가할 수 없습니다."); + } + + // 평가 점수 저장 + saveEvaluation(request.getScore(), evaluatee, memberClubMember); + + // 평가 점수 평균 계산 및 업데이트 + updateAverageMannersScore(evaluatee); + + // 평가자가 해당 멤버에게 평가한 횟수 반환 + return new EvaluateMemberResponse((int) (evaluationCount + 1)); + } + + public MemberRateResponse getMemberRateCountAndCount(String email, Long clubId, Long evaluateeId) { + Member member = getMemberByEmail(email); + Member evaluatee = getMemberById(evaluateeId); + Club club = getClubById(clubId); + + // 해당 멤버가 해당 모임에 가입되어 있는지 확인 + ClubMember memberClubMember = getClubMember(club, member); + validateClubMember(club, member, evaluatee); + + // 해당 멤버의 평가 점수 평균 조회 + double averageScore = evaluatee.getAverageMannersScore().doubleValue(); + + // 해당 멤버에게 평가한 횟수 조회 + long evaluationCount = mannerRepository.countByMemberAndClubMember(evaluatee, memberClubMember); + + return MemberRateResponse.builder() + .rateCount((int) evaluationCount) + .userName(evaluatee.getUsername()) + .averageMannersScore(BigDecimal.valueOf(averageScore)) + .profileImageUrl(evaluatee.getProfileImageUrl()) + .build(); + } + + private Member getMemberByEmail(String email) { + return memberRepository.findByEmail(email) + .orElseThrow(() -> new IllegalArgumentException("존재하지 않는 사용자입니다.")); + } + + private Member getMemberById(Long evaluateeId) { + return memberRepository.findById(evaluateeId) + .orElseThrow(() -> new IllegalArgumentException("존재하지 않는 사용자입니다.")); + } + + private Club getClubById(Long clubId) { + return clubRepository.findById(clubId) + .orElseThrow(() -> new IllegalArgumentException("존재하지 않는 모임입니다.")); + } + + private void validateClubMember(Club club, Member evaluator, Member evaluatee) { + boolean isMemberJoined = club.getClubMembers().stream() + .anyMatch(cm -> cm.getMember().getId().equals(evaluator.getId())); + boolean isEvaluateeJoined = club.getClubMembers().stream() + .anyMatch(cm -> cm.getMember().getId().equals(evaluatee.getId())); + if (!isMemberJoined || !isEvaluateeJoined) { + throw new IllegalArgumentException("해당 사용자는 해당 모임에 가입되어 있지 않습니다."); + } + } + + private ClubMember getClubMember(Club club, Member member) { + return club.getClubMembers().stream() + .filter(cm -> cm.getMember().equals(member)) + .findFirst() + .orElseThrow(() -> new IllegalArgumentException("해당 멤버를 클럽 멤버에서 찾을 수 없습니다.")); + } + + private void saveEvaluation(int score, Member evaluatee, ClubMember memberClubMember) { + Manner manner = Manner.builder() + .score(score) + .member(evaluatee) + .clubMember(memberClubMember) + .build(); + mannerRepository.save(manner); + } + + private void updateAverageMannersScore(Member evaluatee) { + List allMannersForEvaluatee = mannerRepository.findByMember(evaluatee); + double averageScore = allMannersForEvaluatee.stream() + .mapToInt(Manner::getScore) + .average() + .getAsDouble(); + evaluatee.setAverageMannersScore(BigDecimal.valueOf(averageScore)); + memberRepository.save(evaluatee); + } + +}