diff --git a/src/main/java/com/pawwithu/connectdog/domain/intermediary/controller/IntermediaryController.java b/src/main/java/com/pawwithu/connectdog/domain/intermediary/controller/IntermediaryController.java index 11d833a0..390bba5c 100644 --- a/src/main/java/com/pawwithu/connectdog/domain/intermediary/controller/IntermediaryController.java +++ b/src/main/java/com/pawwithu/connectdog/domain/intermediary/controller/IntermediaryController.java @@ -1,5 +1,6 @@ package com.pawwithu.connectdog.domain.intermediary.controller; +import com.pawwithu.connectdog.domain.intermediary.dto.request.IntermediaryMyProfileRequest; import com.pawwithu.connectdog.domain.intermediary.dto.response.*; import com.pawwithu.connectdog.domain.intermediary.service.IntermediaryService; import com.pawwithu.connectdog.error.dto.ErrorResponse; @@ -9,14 +10,14 @@ import io.swagger.v3.oas.annotations.responses.ApiResponse; import io.swagger.v3.oas.annotations.security.SecurityRequirement; import io.swagger.v3.oas.annotations.tags.Tag; +import jakarta.validation.Valid; import lombok.RequiredArgsConstructor; import org.springframework.data.domain.Pageable; import org.springframework.http.ResponseEntity; import org.springframework.security.core.annotation.AuthenticationPrincipal; import org.springframework.security.core.userdetails.UserDetails; -import org.springframework.web.bind.annotation.GetMapping; -import org.springframework.web.bind.annotation.PathVariable; -import org.springframework.web.bind.annotation.RestController; +import org.springframework.web.bind.annotation.*; +import org.springframework.web.multipart.MultipartFile; import java.util.List; @@ -94,4 +95,20 @@ public ResponseEntity getIntermediaryHome(@Authenti IntermediaryGetHomeResponse response = intermediaryService.getIntermediaryHome(loginUser.getUsername()); return ResponseEntity.ok(response); } + + @Operation(summary = "이동봉사 중개 - 마이페이지 프로필 수정", description = "마이페이지 프로필을 수정합니다.", + security = { @SecurityRequirement(name = "bearer-key") }, + responses = {@ApiResponse(responseCode = "204", description = "마이페이지 프로필 수정 성공") + , @ApiResponse(responseCode = "400" + , description = "V1, 한줄 소개는 50자 이하로 입력해 주세요. \t\n V1, 문의 받을 연락처는 50자 이하로 입력해 주세요. \t\n V1, 안내사항은 200자 이하로 입력해 주세요. \t\n M2, 해당 이동봉사 중개를 찾을 수 없습니다." + , content = @Content(schema = @Schema(implementation = ErrorResponse.class))) + }) + @PatchMapping("/intermediaries/my/profile") + public ResponseEntity intermediaryMyProfile(@AuthenticationPrincipal UserDetails loginUser, + @RequestPart @Valid IntermediaryMyProfileRequest request, + @RequestPart(name = "profileImage", required = false) MultipartFile profileImage) { + intermediaryService.intermediaryMyProfile(loginUser.getUsername(), request, profileImage); + return ResponseEntity.noContent().build(); + } + } diff --git a/src/main/java/com/pawwithu/connectdog/domain/intermediary/dto/request/IntermediaryMyProfileRequest.java b/src/main/java/com/pawwithu/connectdog/domain/intermediary/dto/request/IntermediaryMyProfileRequest.java new file mode 100644 index 00000000..0cd8ce07 --- /dev/null +++ b/src/main/java/com/pawwithu/connectdog/domain/intermediary/dto/request/IntermediaryMyProfileRequest.java @@ -0,0 +1,13 @@ +package com.pawwithu.connectdog.domain.intermediary.dto.request; + +import jakarta.validation.constraints.Size; + +public record IntermediaryMyProfileRequest( + @Size(max=50, message = "한줄 소개는 50자 이하로 입력해 주세요.") + String intro, + @Size(max=50, message = "문의 받을 연락처는 50자 이하로 입력해 주세요.") + String contact, + @Size(max=200, message = "안내사항은 200자 이하로 입력해 주세요.") + String guide +) { +} diff --git a/src/main/java/com/pawwithu/connectdog/domain/intermediary/entity/Intermediary.java b/src/main/java/com/pawwithu/connectdog/domain/intermediary/entity/Intermediary.java index c450ae09..e04d3c99 100644 --- a/src/main/java/com/pawwithu/connectdog/domain/intermediary/entity/Intermediary.java +++ b/src/main/java/com/pawwithu/connectdog/domain/intermediary/entity/Intermediary.java @@ -49,4 +49,17 @@ public Intermediary(String email, String password, String name, String url, Stri public void passwordEncode(PasswordEncoder passwordEncoder) { this.password = passwordEncoder.encode(this.password); } + + public void updateProfile(String profileImage, String intro, String contact, String guide) { + this.profileImage = profileImage; + this.intro = intro; + this.contact = contact; + this.guide = guide; + } + + public void updateProfileWithoutImage(String intro, String contact, String guide) { + this.intro = intro; + this.contact = contact; + this.guide = guide; + } } diff --git a/src/main/java/com/pawwithu/connectdog/domain/intermediary/service/IntermediaryService.java b/src/main/java/com/pawwithu/connectdog/domain/intermediary/service/IntermediaryService.java index b4a5d974..a4f9c171 100644 --- a/src/main/java/com/pawwithu/connectdog/domain/intermediary/service/IntermediaryService.java +++ b/src/main/java/com/pawwithu/connectdog/domain/intermediary/service/IntermediaryService.java @@ -1,6 +1,8 @@ package com.pawwithu.connectdog.domain.intermediary.service; +import com.pawwithu.connectdog.common.s3.FileService; import com.pawwithu.connectdog.domain.dogStatus.repository.CustomDogStatusRepository; +import com.pawwithu.connectdog.domain.intermediary.dto.request.IntermediaryMyProfileRequest; import com.pawwithu.connectdog.domain.intermediary.dto.response.*; import com.pawwithu.connectdog.domain.intermediary.entity.Intermediary; import com.pawwithu.connectdog.domain.intermediary.repository.IntermediaryRepository; @@ -13,6 +15,7 @@ import org.springframework.data.domain.Pageable; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; +import org.springframework.web.multipart.MultipartFile; import java.util.List; import java.util.Map; @@ -29,6 +32,7 @@ public class IntermediaryService { private final CustomPostRepository customPostRepository; private final CustomReviewRepository customReviewRepository; private final CustomDogStatusRepository customDogStatusRepository; + private final FileService fileService; @Transactional(readOnly = true) public List getIntermediaryPosts(Long intermediaryId, Pageable pageable) { @@ -87,4 +91,21 @@ public IntermediaryGetHomeResponse getIntermediaryHome(String email) { countOfPostStatus.getOrDefault(PostStatus.COMPLETED, 0L)); return response; } + + + public void intermediaryMyProfile(String email, IntermediaryMyProfileRequest intermediaryMyProfileRequest, MultipartFile profileFile) { + Intermediary intermediary = intermediaryRepository.findByEmail(email).orElseThrow(() -> new BadRequestException(INTERMEDIARY_NOT_FOUND)); + + String intro = intermediaryMyProfileRequest.intro(); + String contact = intermediaryMyProfileRequest.contact(); + String guide = intermediaryMyProfileRequest.guide(); + + String profileImage = fileService.uploadFile(profileFile, "intermediary/profileImage"); + if (profileImage != null) { + intermediary.updateProfile(profileImage, intro, contact, guide); + } else { + intermediary.updateProfileWithoutImage(intro, contact, guide); + } + + } } diff --git a/src/test/java/com/pawwithu/connectdog/domain/intermediary/controller/IntermediaryControllerTest.java b/src/test/java/com/pawwithu/connectdog/domain/intermediary/controller/IntermediaryControllerTest.java index 1980e214..ceebf0e1 100644 --- a/src/test/java/com/pawwithu/connectdog/domain/intermediary/controller/IntermediaryControllerTest.java +++ b/src/test/java/com/pawwithu/connectdog/domain/intermediary/controller/IntermediaryControllerTest.java @@ -1,6 +1,7 @@ package com.pawwithu.connectdog.domain.intermediary.controller; import com.fasterxml.jackson.databind.ObjectMapper; +import com.pawwithu.connectdog.domain.intermediary.dto.request.IntermediaryMyProfileRequest; import com.pawwithu.connectdog.domain.intermediary.dto.response.*; import com.pawwithu.connectdog.domain.intermediary.service.IntermediaryService; import com.pawwithu.connectdog.utils.TestUserArgumentResolver; @@ -13,11 +14,16 @@ import org.springframework.data.domain.PageRequest; import org.springframework.data.domain.Pageable; import org.springframework.data.web.PageableHandlerMethodArgumentResolver; +import org.springframework.http.HttpMethod; +import org.springframework.http.MediaType; +import org.springframework.mock.web.MockMultipartFile; import org.springframework.test.web.servlet.MockMvc; import org.springframework.test.web.servlet.ResultActions; +import org.springframework.test.web.servlet.request.MockMvcRequestBuilders; import org.springframework.test.web.servlet.setup.MockMvcBuilders; import org.springframework.web.filter.CharacterEncodingFilter; +import java.nio.charset.StandardCharsets; import java.time.LocalDate; import java.util.ArrayList; import java.util.List; @@ -27,6 +33,7 @@ import static org.mockito.Mockito.times; import static org.mockito.Mockito.verify; import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get; +import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.patch; import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; @ExtendWith(MockitoExtension.class) @@ -167,5 +174,23 @@ void setUp() { verify(intermediaryService, times(1)).getIntermediaryHome(anyString()); } + @Test + void 이동봉사_중개_마이페이지_프로필_수정() throws Exception { + // given + IntermediaryMyProfileRequest request = new IntermediaryMyProfileRequest("한줄 소개 변경", "문의 받을 연락처 변경", "안내사항 변경"); + MockMultipartFile profileImage = new MockMultipartFile("profileImage", "profileImage.png", "multipart/form-data", "uploadFile".getBytes(StandardCharsets.UTF_8)); + MockMultipartFile intermediaryMyProfileRequest = new MockMultipartFile("request", null, "application/json", objectMapper.writeValueAsString(request).getBytes(StandardCharsets.UTF_8)); + + // when + ResultActions result = mockMvc.perform(MockMvcRequestBuilders + .multipart(HttpMethod.PATCH, "/intermediaries/my/profile") + .file(profileImage) + .file(intermediaryMyProfileRequest) + .accept(MediaType.APPLICATION_JSON) + .contentType(MediaType.MULTIPART_FORM_DATA)); + // then + result.andExpect(status().isNoContent()); + verify(intermediaryService, times(1)).intermediaryMyProfile(anyString(), any(), any()); + } } \ No newline at end of file