diff --git a/src/main/java/com/example/solidconnection/location/country/repository/InterestedCountryRepository.java b/src/main/java/com/example/solidconnection/location/country/repository/InterestedCountryRepository.java index 0d555b7bb..b7e12a285 100644 --- a/src/main/java/com/example/solidconnection/location/country/repository/InterestedCountryRepository.java +++ b/src/main/java/com/example/solidconnection/location/country/repository/InterestedCountryRepository.java @@ -7,4 +7,6 @@ public interface InterestedCountryRepository extends JpaRepository { List findAllBySiteUserId(long siteUserId); + + void deleteAllBySiteUserId(long siteUserId); } diff --git a/src/main/java/com/example/solidconnection/location/country/service/InterestedCountryService.java b/src/main/java/com/example/solidconnection/location/country/service/InterestedCountryService.java index 8166de968..9e2fa4060 100644 --- a/src/main/java/com/example/solidconnection/location/country/service/InterestedCountryService.java +++ b/src/main/java/com/example/solidconnection/location/country/service/InterestedCountryService.java @@ -24,4 +24,15 @@ public void saveInterestedCountry(SiteUser siteUser, List koreanNames) { .toList(); interestedCountryRepository.saveAll(interestedCountries); } + + @Transactional + public void updateInterestedCountry(SiteUser siteUser, List koreanNames) { + interestedCountryRepository.deleteAllBySiteUserId(siteUser.getId()); + + List interestedCountries = countryRepository.findAllByKoreanNameIn(koreanNames) + .stream() + .map(country -> new InterestedCountry(siteUser, country)) + .toList(); + interestedCountryRepository.saveAll(interestedCountries); + } } diff --git a/src/main/java/com/example/solidconnection/location/region/repository/InterestedRegionRepository.java b/src/main/java/com/example/solidconnection/location/region/repository/InterestedRegionRepository.java index 335218c08..367eb2164 100644 --- a/src/main/java/com/example/solidconnection/location/region/repository/InterestedRegionRepository.java +++ b/src/main/java/com/example/solidconnection/location/region/repository/InterestedRegionRepository.java @@ -7,4 +7,6 @@ public interface InterestedRegionRepository extends JpaRepository { List findAllBySiteUserId(long siteUserId); + + void deleteAllBySiteUserId(long siteUserId); } diff --git a/src/main/java/com/example/solidconnection/location/region/service/InterestedRegionService.java b/src/main/java/com/example/solidconnection/location/region/service/InterestedRegionService.java index 6dc71263e..2c8c592cd 100644 --- a/src/main/java/com/example/solidconnection/location/region/service/InterestedRegionService.java +++ b/src/main/java/com/example/solidconnection/location/region/service/InterestedRegionService.java @@ -24,4 +24,15 @@ public void saveInterestedRegion(SiteUser siteUser, List koreanNames) { .toList(); interestedRegionRepository.saveAll(interestedRegions); } + + @Transactional + public void updateInterestedRegion(SiteUser siteUser, List koreanNames) { + interestedRegionRepository.deleteAllBySiteUserId(siteUser.getId()); + + List interestedRegions = regionRepository.findAllByKoreanNameIn(koreanNames) + .stream() + .map(region -> new InterestedRegion(siteUser, region)) + .toList(); + interestedRegionRepository.saveAll(interestedRegions); + } } diff --git a/src/main/java/com/example/solidconnection/siteuser/controller/MyPageController.java b/src/main/java/com/example/solidconnection/siteuser/controller/MyPageController.java index 534b6c361..00c3077e3 100644 --- a/src/main/java/com/example/solidconnection/siteuser/controller/MyPageController.java +++ b/src/main/java/com/example/solidconnection/siteuser/controller/MyPageController.java @@ -2,6 +2,7 @@ import com.example.solidconnection.common.resolver.AuthorizedUser; +import com.example.solidconnection.siteuser.dto.LocationUpdateRequest; import com.example.solidconnection.siteuser.dto.MyPageResponse; import com.example.solidconnection.siteuser.dto.PasswordUpdateRequest; import com.example.solidconnection.siteuser.service.MyPageService; @@ -49,4 +50,13 @@ public ResponseEntity updatePassword( myPageService.updatePassword(siteUserId, request); return ResponseEntity.ok().build(); } + + @PatchMapping("/interested-location") + public ResponseEntity updateLocation( + @AuthorizedUser long siteUserId, + @RequestBody @Valid LocationUpdateRequest request + ) { + myPageService.updateLocation(siteUserId, request); + return ResponseEntity.ok().build(); + } } diff --git a/src/main/java/com/example/solidconnection/siteuser/dto/LocationUpdateRequest.java b/src/main/java/com/example/solidconnection/siteuser/dto/LocationUpdateRequest.java new file mode 100644 index 000000000..2bb38e9cc --- /dev/null +++ b/src/main/java/com/example/solidconnection/siteuser/dto/LocationUpdateRequest.java @@ -0,0 +1,10 @@ +package com.example.solidconnection.siteuser.dto; + +import java.util.List; + +public record LocationUpdateRequest( + List interestedRegions, + List interestedCountries +) { + +} diff --git a/src/main/java/com/example/solidconnection/siteuser/service/MyPageService.java b/src/main/java/com/example/solidconnection/siteuser/service/MyPageService.java index d1d6e340c..d48de9bfa 100644 --- a/src/main/java/com/example/solidconnection/siteuser/service/MyPageService.java +++ b/src/main/java/com/example/solidconnection/siteuser/service/MyPageService.java @@ -8,6 +8,8 @@ import static com.example.solidconnection.common.exception.ErrorCode.USER_NOT_FOUND; import com.example.solidconnection.common.exception.CustomException; +import com.example.solidconnection.location.country.service.InterestedCountryService; +import com.example.solidconnection.location.region.service.InterestedRegionService; import com.example.solidconnection.location.country.repository.CountryRepository; import com.example.solidconnection.mentor.domain.Mentor; import com.example.solidconnection.mentor.repository.MentorRepository; @@ -16,6 +18,7 @@ import com.example.solidconnection.s3.service.S3Service; import com.example.solidconnection.siteuser.domain.Role; import com.example.solidconnection.siteuser.domain.SiteUser; +import com.example.solidconnection.siteuser.dto.LocationUpdateRequest; import com.example.solidconnection.siteuser.dto.MyPageResponse; import com.example.solidconnection.siteuser.dto.PasswordUpdateRequest; import com.example.solidconnection.siteuser.repository.SiteUserRepository; @@ -45,6 +48,8 @@ public class MyPageService { private final MentorRepository mentorRepository; private final UniversityRepository universityRepository; private final S3Service s3Service; + private final InterestedCountryService interestedCountryService; + private final InterestedRegionService interestedRegionService; /* * 마이페이지 정보를 조회한다. @@ -132,4 +137,13 @@ private void validatePasswordMatch(String currentPassword, String userPassword) throw new CustomException(PASSWORD_MISMATCH); } } + + @Transactional + public void updateLocation(long siteUserId, LocationUpdateRequest request) { + SiteUser siteUser = siteUserRepository.findById(siteUserId) + .orElseThrow(() -> new CustomException(USER_NOT_FOUND)); + + interestedCountryService.updateInterestedCountry(siteUser, request.interestedCountries()); + interestedRegionService.updateInterestedRegion(siteUser, request.interestedRegions()); + } } diff --git a/src/test/java/com/example/solidconnection/siteuser/service/MyPageServiceTest.java b/src/test/java/com/example/solidconnection/siteuser/service/MyPageServiceTest.java index f852909c6..d8e5c950f 100644 --- a/src/test/java/com/example/solidconnection/siteuser/service/MyPageServiceTest.java +++ b/src/test/java/com/example/solidconnection/siteuser/service/MyPageServiceTest.java @@ -1,10 +1,13 @@ package com.example.solidconnection.siteuser.service; import static com.example.solidconnection.common.exception.ErrorCode.CAN_NOT_CHANGE_NICKNAME_YET; +import static com.example.solidconnection.common.exception.ErrorCode.PASSWORD_MISMATCH; import static com.example.solidconnection.siteuser.service.MyPageService.MIN_DAYS_BETWEEN_NICKNAME_CHANGES; import static com.example.solidconnection.siteuser.service.MyPageService.NICKNAME_LAST_CHANGE_DATE_FORMAT; import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.assertThatThrownBy; import static org.assertj.core.api.AssertionsForClassTypes.assertThatCode; +import static org.junit.jupiter.api.Assertions.assertAll; import static org.mockito.BDDMockito.any; import static org.mockito.BDDMockito.eq; import static org.mockito.BDDMockito.given; @@ -16,6 +19,10 @@ import com.example.solidconnection.location.country.domain.InterestedCountry; import com.example.solidconnection.location.country.fixture.CountryFixture; import com.example.solidconnection.location.country.repository.InterestedCountryRepository; +import com.example.solidconnection.location.region.domain.InterestedRegion; +import com.example.solidconnection.location.region.domain.Region; +import com.example.solidconnection.location.region.fixture.RegionFixture; +import com.example.solidconnection.location.region.repository.InterestedRegionRepository; import com.example.solidconnection.mentor.fixture.MentorFixture; import com.example.solidconnection.s3.domain.ImgType; import com.example.solidconnection.s3.dto.UploadedFileUrlResponse; @@ -23,7 +30,9 @@ import com.example.solidconnection.siteuser.domain.AuthType; import com.example.solidconnection.siteuser.domain.Role; import com.example.solidconnection.siteuser.domain.SiteUser; +import com.example.solidconnection.siteuser.dto.LocationUpdateRequest; import com.example.solidconnection.siteuser.dto.MyPageResponse; +import com.example.solidconnection.siteuser.dto.PasswordUpdateRequest; import com.example.solidconnection.siteuser.fixture.SiteUserFixture; import com.example.solidconnection.siteuser.fixture.SiteUserFixtureBuilder; import com.example.solidconnection.siteuser.repository.SiteUserRepository; @@ -33,7 +42,7 @@ import com.example.solidconnection.university.fixture.UnivApplyInfoFixture; import com.example.solidconnection.university.repository.LikedUnivApplyInfoRepository; import java.time.LocalDateTime; -import org.junit.jupiter.api.Assertions; +import java.util.List; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.DisplayName; import org.junit.jupiter.api.Nested; @@ -62,6 +71,9 @@ class MyPageServiceTest { @Autowired private InterestedCountryRepository interestedCountryRepository; + @Autowired + private InterestedRegionRepository interestedRegionRepository; + @Autowired private SiteUserFixture siteUserFixture; @@ -74,6 +86,9 @@ class MyPageServiceTest { @Autowired private UnivApplyInfoFixture univApplyInfoFixture; + @Autowired + private RegionFixture regionFixture; + @Autowired private SiteUserFixtureBuilder siteUserFixtureBuilder; @@ -99,7 +114,7 @@ void setUp() { MyPageResponse response = myPageService.getMyPageInfo(user.getId()); // then - Assertions.assertAll( + assertAll( () -> assertThat(response.nickname()).isEqualTo(user.getNickname()), () -> assertThat(response.profileImageUrl()).isEqualTo(user.getProfileImageUrl()), () -> assertThat(response.role()).isEqualTo(user.getRole()), @@ -124,7 +139,7 @@ void setUp() { MyPageResponse response = myPageService.getMyPageInfo(mentorUser.getId()); // then - Assertions.assertAll( + assertAll( () -> assertThat(response.nickname()).isEqualTo(mentorUser.getNickname()), () -> assertThat(response.profileImageUrl()).isEqualTo(mentorUser.getProfileImageUrl()), () -> assertThat(response.role()).isEqualTo(mentorUser.getRole()), @@ -263,4 +278,139 @@ void setUp() { .hasMessage(createExpectedErrorMessage(modifiedAt)); } } + + @Nested + class 비밀번호_변경_테스트 { + + private String currentPassword; + private String newPassword; + + @BeforeEach + void setUp() { + currentPassword = "currentPassword123"; + newPassword = "newPassword123"; + + user.updatePassword(passwordEncoder.encode(currentPassword)); + siteUserRepository.save(user); + } + + @Test + void 비밀번호를_성공적으로_변경한다() { + // given + PasswordUpdateRequest request = new PasswordUpdateRequest(currentPassword, newPassword, newPassword); + + // when + myPageService.updatePassword(user.getId(), request); + + // then + SiteUser updatedUser = siteUserRepository.findById(user.getId()).get(); + assertAll( + () -> assertThat(passwordEncoder.matches(newPassword, updatedUser.getPassword())).isTrue(), + () -> assertThat(passwordEncoder.matches(currentPassword, updatedUser.getPassword())).isFalse() + ); + } + + @Test + void 현재_비밀번호가_일치하지_않으면_예외가_발생한다() { + // given + String wrongPassword = "wrongPassword"; + PasswordUpdateRequest request = new PasswordUpdateRequest(wrongPassword, newPassword, newPassword); + + // when & then + assertThatThrownBy(() -> myPageService.updatePassword(user.getId(), request)) + .isInstanceOf(CustomException.class) + .hasMessage(PASSWORD_MISMATCH.getMessage()); + } + } + + @Nested + class 관심_지역_및_국가_변경_테스트 { + + private Country 미국; + private Country 캐나다; + private Country 일본; + private Region 영미권; + private Region 아시아; + + @BeforeEach + void setUp() { + 미국 = countryFixture.미국(); + 캐나다 = countryFixture.캐나다(); + 일본 = countryFixture.일본(); + 영미권 = regionFixture.영미권(); + 아시아 = regionFixture.아시아(); + } + + @Test + void 관심_지역과_국가를_성공적으로_수정한다() { + // given + interestedCountryRepository.save(new InterestedCountry(user, 미국)); + interestedRegionRepository.save(new InterestedRegion(user, 영미권)); + + List newCountries = List.of(캐나다.getKoreanName(), 일본.getKoreanName()); + List newRegions = List.of(아시아.getKoreanName()); + LocationUpdateRequest request = new LocationUpdateRequest(newRegions, newCountries); + + // when + myPageService.updateLocation(user.getId(), request); + + // then + List updatedCountries = interestedCountryRepository.findAllBySiteUserId(user.getId()); + List updatedRegions = interestedRegionRepository.findAllBySiteUserId(user.getId()); + + assertAll( + () -> assertThat(updatedCountries) + .extracting(InterestedCountry::getCountryCode) + .containsExactlyInAnyOrder(캐나다.getCode(), 일본.getCode()), + () -> assertThat(updatedRegions) + .extracting(InterestedRegion::getRegionCode) + .containsExactly(아시아.getCode()) + ); + } + + @Test + void 기존에_관심_지역과_국가가_없어도_성공적으로_추가된다() { + // given + List newCountries = List.of(미국.getKoreanName()); + List newRegions = List.of(영미권.getKoreanName()); + LocationUpdateRequest request = new LocationUpdateRequest(newRegions, newCountries); + + // when + myPageService.updateLocation(user.getId(), request); + + // then + List updatedCountries = interestedCountryRepository.findAllBySiteUserId(user.getId()); + List updatedRegions = interestedRegionRepository.findAllBySiteUserId(user.getId()); + + assertAll( + () -> assertThat(updatedCountries) + .extracting(InterestedCountry::getCountryCode) + .containsExactly(미국.getCode()), + () -> assertThat(updatedRegions) + .extracting(InterestedRegion::getRegionCode) + .containsExactly(영미권.getCode()) + ); + } + + @Test + void 빈_리스트를_전달하면_모든_관심_지역과_국가가_삭제된다() { + // given + interestedCountryRepository.save(new InterestedCountry(user, 미국)); + interestedRegionRepository.save(new InterestedRegion(user, 영미권)); + + LocationUpdateRequest request = new LocationUpdateRequest(List.of(), List.of()); + + // when + myPageService.updateLocation(user.getId(), request); + + // then + List updatedCountries = interestedCountryRepository.findAllBySiteUserId(user.getId()); + List updatedRegions = interestedRegionRepository.findAllBySiteUserId(user.getId()); + + assertAll( + () -> assertThat(updatedCountries).isEmpty(), + () -> assertThat(updatedRegions).isEmpty() + ); + } + } }