Skip to content

Commit

Permalink
fix: 충돌해결
Browse files Browse the repository at this point in the history
  • Loading branch information
donghyun0304 committed Mar 24, 2024
2 parents 21a9718 + 848233b commit 6562dac
Show file tree
Hide file tree
Showing 10 changed files with 310 additions and 7 deletions.
6 changes: 6 additions & 0 deletions src/main/java/com/example/demo/config/MapperConfig.java
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
import com.example.demo.mapper.MemberMapper;
import com.example.demo.mapper.ReviewMapper;
import com.example.demo.mapper.SnsDetailMapper;
import com.example.demo.mapper.StudyMemberMapper;
import com.example.demo.mapper.StudyOnceMapper;

@Configuration
Expand Down Expand Up @@ -42,4 +43,9 @@ public StudyOnceMapper studyOnceMapper() {
public MemberMapper memberMapper() {
return new MemberMapper();
}

@Bean
public StudyMemberMapper studyMemberMapper() {
return new StudyMemberMapper();
}
}
30 changes: 30 additions & 0 deletions src/main/java/com/example/demo/controller/ProfileController.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
package com.example.demo.controller;

import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestHeader;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import com.example.demo.domain.auth.CafegoryTokenManager;
import com.example.demo.dto.profile.ProfileResponse;
import com.example.demo.service.profile.ProfileService;

import lombok.RequiredArgsConstructor;

@RestController
@RequestMapping("/profile")
@RequiredArgsConstructor
public class ProfileController {
private final ProfileService profileService;
private final CafegoryTokenManager cafegoryTokenManager;

@GetMapping("/{memberId:[0-9]+}")
public ResponseEntity<ProfileResponse> get(@PathVariable("memberId") Long targetMemberId,
@RequestHeader("Authorization") String authorization) {
long requestMemberId = cafegoryTokenManager.getIdentityId(authorization);
ProfileResponse profileResponse = profileService.get(requestMemberId, targetMemberId);
return ResponseEntity.ok(profileResponse);
}
}
12 changes: 12 additions & 0 deletions src/main/java/com/example/demo/dto/profile/ProfileResponse.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
package com.example.demo.dto.profile;

import lombok.Getter;
import lombok.RequiredArgsConstructor;

@RequiredArgsConstructor
@Getter
public class ProfileResponse {
private final String name;
private final String thumbnailImg;
private final String introduction;
}
3 changes: 2 additions & 1 deletion src/main/java/com/example/demo/exception/ExceptionType.java
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,8 @@ public enum ExceptionType {
CAFE_NOT_FOUND(NOT_FOUND, "없는 카페입니다."),
CAFE_INVALID_BUSINESS_TIME_RANGE(BAD_REQUEST, "영업시간이 허용된 범위를 벗어났습니다."),
CAFE_NOT_FOUND_DAY_OF_WEEK(INTERNAL_SERVER_ERROR, "현재 요일과 일치하는 요일을 찾을 수 없습니다."),
STUDY_MEMBER_NOT_FOUND(NOT_FOUND, "없는 스터디멤버입니다.");
STUDY_MEMBER_NOT_FOUND(NOT_FOUND, "없는 스터디멤버입니다."),
PROFILE_GET_PERMISSION_DENIED(FORBIDDEN, "프로필을 조회할 권한이 없는 상대입니다.");

private final HttpStatus errStatus;
private final String errorMessage;
Expand Down
15 changes: 15 additions & 0 deletions src/main/java/com/example/demo/mapper/StudyMemberMapper.java
Original file line number Diff line number Diff line change
@@ -1,5 +1,20 @@
package com.example.demo.mapper;

import java.util.List;
import java.util.stream.Collectors;

import com.example.demo.domain.StudyMember;
import com.example.demo.dto.MemberResponse;

public class StudyMemberMapper {

public List<MemberResponse> toMemberResponses(List<StudyMember> studyMembers) {
return studyMembers.stream()
.map(studyMember -> new MemberResponse(
studyMember.getMember().getId(),
studyMember.getMember().getName(),
studyMember.getMember().getThumbnailImage().getThumbnailImage()))
.collect(Collectors.toList());
}

}
Original file line number Diff line number Diff line change
@@ -1,10 +1,14 @@
package com.example.demo.repository;

import java.util.List;

import org.springframework.data.jpa.repository.JpaRepository;

import com.example.demo.domain.StudyOnceImpl;

public interface StudyOnceRepository extends JpaRepository<StudyOnceImpl, Long>, StudyOnceRepositoryCustom {

boolean existsByLeaderId(Long leaderId);

List<StudyOnceImpl> findByLeaderId(Long leaderId);
}
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@
import com.example.demo.dto.UpdateAttendanceRequest;
import com.example.demo.dto.UpdateAttendanceResponse;
import com.example.demo.exception.CafegoryException;
import com.example.demo.mapper.StudyMemberMapper;
import com.example.demo.mapper.StudyOnceMapper;
import com.example.demo.repository.MemberRepository;
import com.example.demo.repository.StudyMemberRepository;
Expand All @@ -45,6 +46,7 @@ public class StudyOnceServiceImpl implements StudyOnceService {
private final MemberRepository memberRepository;
private final StudyMemberRepository studyMemberRepository;
private final StudyOnceMapper studyOnceMapper;
private final StudyMemberMapper studyMemberMapper;

@Override
public void tryJoin(long memberIdThatExpectedToJoin, long studyId) {
Expand Down Expand Up @@ -207,12 +209,7 @@ public Long changeCafe(Long requestMemberId, Long studyOnceId, final Long changi
@Override
public StudyMembersResponse findStudyMembersById(Long studyOnceId) {
StudyOnceImpl studyOnce = findStudyOnceById(studyOnceId);
List<MemberResponse> memberResponses = studyOnce.getStudyMembers().stream()
.map(studyMember -> new MemberResponse(
studyMember.getMember().getId(),
studyMember.getMember().getName(),
studyMember.getMember().getThumbnailImage().getThumbnailImage()))
.collect(Collectors.toList());
List<MemberResponse> memberResponses = studyMemberMapper.toMemberResponses(studyOnce.getStudyMembers());
return new StudyMembersResponse(memberResponses);
}

Expand Down
13 changes: 13 additions & 0 deletions src/main/java/com/example/demo/service/profile/ProfileService.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
package com.example.demo.service.profile;

import java.time.LocalDateTime;

import com.example.demo.dto.profile.ProfileResponse;

public interface ProfileService {
default ProfileResponse get(Long requestMemberID, Long targetMemberID) {
return get(requestMemberID, targetMemberID, LocalDateTime.now());
}

ProfileResponse get(Long requestMemberID, Long targetMemberID, LocalDateTime baseDateTime);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,99 @@
package com.example.demo.service.profile;

import static com.example.demo.exception.ExceptionType.*;

import java.time.LocalDate;
import java.time.LocalDateTime;
import java.util.List;
import java.util.Set;
import java.util.stream.Collectors;

import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import com.example.demo.domain.MemberImpl;
import com.example.demo.domain.StudyMember;
import com.example.demo.domain.StudyOnceImpl;
import com.example.demo.dto.profile.ProfileResponse;
import com.example.demo.exception.CafegoryException;
import com.example.demo.repository.MemberRepository;
import com.example.demo.repository.StudyMemberRepository;
import com.example.demo.repository.StudyOnceRepository;

import lombok.RequiredArgsConstructor;

@Transactional
@Service
@RequiredArgsConstructor
public class ProfileServiceImpl implements ProfileService {
private final MemberRepository memberRepository;
private final StudyOnceRepository studyOnceRepository;
private final StudyMemberRepository studyMemberRepository;

@Override
public ProfileResponse get(Long requestMemberID, Long targetMemberID, LocalDateTime baseDateTime) {
if (isOwnerOfProfile(requestMemberID, targetMemberID)) {
return makeProfileResponse(targetMemberID);
}
if (isAllowedCauseStudyLeader(requestMemberID, targetMemberID)) {
return makeProfileResponse(targetMemberID);
}
if (isAllowedCauseSameStudyOnceMember(requestMemberID, targetMemberID, baseDateTime)) {
return makeProfileResponse(targetMemberID);
}
throw new CafegoryException(PROFILE_GET_PERMISSION_DENIED);
}

private ProfileResponse makeProfileResponse(Long targetMemberID) {
MemberImpl member = memberRepository.findById(targetMemberID).orElseThrow();
return new ProfileResponse(member.getName(), member.getThumbnailImage().getThumbnailImage(), "");
}

private boolean isOwnerOfProfile(Long requestMemberID, Long targetMemberID) {
if (requestMemberID == null || targetMemberID == null) {
return false;
}
return requestMemberID.equals(targetMemberID);
}

private boolean isAllowedCauseStudyLeader(Long requestMemberID, Long targetMemberID) {
List<StudyOnceImpl> studyOnceByLeaderID = findStudyOnceByLeaderID(requestMemberID);
Set<Long> memberIdInStudyOnce = getMemberIdInStudyOnce(studyOnceByLeaderID);
return memberIdInStudyOnce.contains(targetMemberID);
}

private List<StudyOnceImpl> findStudyOnceByLeaderID(Long requestMemberID) {
return studyOnceRepository.findByLeaderId(requestMemberID);
}

private Set<Long> getMemberIdInStudyOnce(List<StudyOnceImpl> byLeaderId) {
return mapToMemberId(byLeaderId.stream()
.flatMap(studyOnce -> studyOnce.getStudyMembers().stream())
.collect(Collectors.toList()));
}

private static Set<Long> mapToMemberId(List<StudyMember> studyMembers) {
return studyMembers.stream()
.map(StudyMember::getMember)
.map(MemberImpl::getId)
.collect(Collectors.toSet());
}

private boolean isAllowedCauseSameStudyOnceMember(Long requestMemberID, Long targetMemberID, LocalDateTime base) {
MemberImpl requestMember = memberRepository.findById(requestMemberID).orElseThrow();
List<StudyMember> studyMembers = findAllSameStudyOnceStudyMembersWith(requestMember, base);
Set<Long> memberIdsThatJoinWithRequestMember = mapToMemberId(studyMembers);
return memberIdsThatJoinWithRequestMember.contains(targetMemberID);
}

private List<StudyMember> findAllSameStudyOnceStudyMembersWith(MemberImpl requestMember, LocalDateTime base) {
LocalDate baseDate = LocalDate.from(base);
return studyMemberRepository.findByMemberAndStudyDate(requestMember, baseDate)
.stream()
.map(StudyMember::getStudy)
.filter(studyOnce -> !studyOnce.canJoin(base))
.filter(studyOnce -> !studyOnce.isEnd())
.flatMap(studyOnce -> studyOnce.getStudyMembers().stream())
.collect(Collectors.toList());
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,126 @@
package com.example.demo.service.profile;

import static com.example.demo.exception.ExceptionType.*;

import java.time.LocalDateTime;

import javax.persistence.EntityManager;

import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.context.annotation.Import;
import org.springframework.transaction.annotation.Transactional;

import com.example.demo.config.TestConfig;
import com.example.demo.domain.Address;
import com.example.demo.domain.CafeImpl;
import com.example.demo.domain.MemberImpl;
import com.example.demo.domain.StudyOnceImpl;
import com.example.demo.domain.ThumbnailImage;
import com.example.demo.dto.StudyOnceCreateRequest;
import com.example.demo.dto.StudyOnceSearchResponse;
import com.example.demo.exception.CafegoryException;
import com.example.demo.service.StudyOnceService;

@SpringBootTest
@Import(TestConfig.class)
@Transactional
class ProfileServiceImplTest {
@Autowired
private ProfileService profileService;
@Autowired
private EntityManager em;
@Autowired
private StudyOnceService studyOnceService;

private long initCafe() {
Address address = new Address("테스트도 테스트시 테스트구 테스트동 ...", "테스트동");
CafeImpl cafe = CafeImpl.builder()
.address(address).build();
em.persist(cafe);
return cafe.getId();
}

private long initMember() {
MemberImpl member = MemberImpl.builder()
.name("테스트")
.email("[email protected]")
.thumbnailImage(ThumbnailImage.builder().thumbnailImage("testUrl").build())
.build();
em.persist(member);
return member.getId();
}

private long initStudy(MemberImpl leader, CafeImpl cafe) {
LocalDateTime start = LocalDateTime.now().plusHours(4);
StudyOnceImpl studyOnce = StudyOnceImpl.builder()
.leader(leader)
.cafe(cafe)
.startDateTime(start)
.endDateTime(start.plusHours(5).minusMinutes(10))
.ableToTalk(true)
.maxMemberCount(5)
.nowMemberCount(1)
.isEnd(false)
.build();
em.persist(studyOnce);
return studyOnce.getId();
}

@Test
@DisplayName("자신이 스터디 장인 카공의 멤버면 프로필 조회 성공")
void successWhenRequestMemberIsLeaderWithTargetMember() {
long cafeId = initCafe();
long requestMemberId = initMember();
long targetMemberId = initMember();
LocalDateTime start = LocalDateTime.now().plusHours(4);
StudyOnceCreateRequest studyOnceCreateRequest = makeStudyOnceCreateRequest(start, start.plusHours(5), cafeId);
StudyOnceSearchResponse study = studyOnceService.createStudy(requestMemberId, studyOnceCreateRequest);
studyOnceService.tryJoin(targetMemberId, study.getStudyOnceId());
Assertions.assertDoesNotThrow(() -> profileService.get(requestMemberId, targetMemberId));
}

@Test
@DisplayName("자신이 참여 확정 상태인 카공의 멤버면 프로필 조회 성공")
void successWhenRequestMemberAndTargetMemberJoinSameStudy() {
long cafeId = initCafe();
long requestMemberId = initMember();
long targetMemberId = initMember();
long studyLeaderId = initMember();
CafeImpl cafe = em.find(CafeImpl.class, cafeId);
MemberImpl leader = em.find(MemberImpl.class, studyLeaderId);
long studyId = initStudy(leader, cafe);

studyOnceService.tryJoin(targetMemberId, studyId);
studyOnceService.tryJoin(requestMemberId, studyId);

Assertions.assertDoesNotThrow(
() -> profileService.get(requestMemberId, targetMemberId, LocalDateTime.now().plusHours(8)));
}

private static StudyOnceCreateRequest makeStudyOnceCreateRequest(LocalDateTime start, LocalDateTime end,
long cafeId) {
return new StudyOnceCreateRequest(cafeId, "테스트 카페", start, end, 4, true);
}

@Test
@DisplayName("자신의 프로필 조회 성공")
void successWhenRequestSelf() {
long requestMemberId = initMember();
Assertions.assertDoesNotThrow(
() -> profileService.get(requestMemberId, requestMemberId));
}

@Test
@DisplayName("프로필 조회 조건을 만족하지 않는 경우 실패")
void failWhenOtherCase() {
long requestMemberId = initMember();
long targetMemberId = initMember();
CafegoryException cafegoryException = Assertions.assertThrows(CafegoryException.class,
() -> profileService.get(requestMemberId, targetMemberId));
Assertions.assertEquals(cafegoryException.getMessage(), PROFILE_GET_PERMISSION_DENIED.getErrorMessage());
}
}

0 comments on commit 6562dac

Please sign in to comment.