Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -122,6 +122,11 @@ public ResponseEntity<RsData<Void>> refreshToken(
.body(new RsData<>("200", "액세스 토큰을 재발급 했습니다.", null));
}

/**
* 확장프로그램의 액세스 토큰 발급을 위한 백그라운드 풀링에 대응하는 API
* @param state 확장프로그램 로그인 시 전달한 state 값.
*/

@GetMapping("/result")
@Operation(summary = "확장프로그램 백그라운드 풀링 대응 API")
public ResponseEntity<RsData<AuthResultData>> pullingResult(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,10 +8,10 @@
import org.springframework.http.ResponseEntity;
import org.springframework.security.core.annotation.AuthenticationPrincipal;
import org.springframework.web.bind.annotation.*;
import org.tuna.zoopzoop.backend.domain.member.dto.req.ReqBodyForEditMember;
import org.tuna.zoopzoop.backend.domain.member.dto.req.ReqBodyForEditMemberName;
import org.tuna.zoopzoop.backend.domain.member.dto.res.ResBodyForEditMemberName;
import org.tuna.zoopzoop.backend.domain.member.dto.res.ResBodyForGetMemberInfo;
import org.tuna.zoopzoop.backend.domain.member.dto.res.ResBodyForGetMemberInfoV2;
import org.tuna.zoopzoop.backend.domain.member.dto.req.ReqBodyForEditMemberProfileImage;
import org.tuna.zoopzoop.backend.domain.member.dto.res.*;
import org.tuna.zoopzoop.backend.domain.member.entity.Member;
import org.tuna.zoopzoop.backend.domain.member.service.MemberService;
import org.tuna.zoopzoop.backend.global.rsData.RsData;
Expand Down Expand Up @@ -62,14 +62,14 @@ public ResponseEntity<RsData<ResBodyForGetMemberInfoV2>> getMemberInfo(
* @param userDetails @AuthenticationPrincipal로 받아오는 현재 사용자 정보
* @param reqBodyForEditMemberName 수정할 닉네임을 받아오는 reqDto
*/
@PutMapping("/edit")
@PutMapping("/edit/name")
@Operation(summary = "사용자 닉네임 수정")
public ResponseEntity<RsData<ResBodyForEditMemberName>> editMemberName(
@AuthenticationPrincipal CustomUserDetails userDetails,
@Valid @RequestBody ReqBodyForEditMemberName reqBodyForEditMemberName
) {
Member member = userDetails.getMember();
member.updateName(reqBodyForEditMemberName.newName());
memberService.updateMemberName(member, reqBodyForEditMemberName.newName());
return ResponseEntity
.status(HttpStatus.OK)
.body(
Expand All @@ -81,12 +81,64 @@ public ResponseEntity<RsData<ResBodyForEditMemberName>> editMemberName(
);
}

/**
* 현재 로그인한 사용자의 프로필 이미지를 변경하는 API
* HTTP METHOD: PUT
* @param userDetails @AuthenticationPrincipal로 받아오는 현재 사용자 정보
* @param reqBodyForEditMemberProfileImage 수정할 프로필 이미지를 받아오는 dto
*/
@PutMapping("/edit/image")
@Operation(summary = "사용자 닉네임 수정")
public ResponseEntity<RsData<ResBodyForEditMemberProfileImage>> editMemberProfileImage(
@AuthenticationPrincipal CustomUserDetails userDetails,
@Valid @RequestBody ReqBodyForEditMemberProfileImage reqBodyForEditMemberProfileImage
) {
Member member = userDetails.getMember();
memberService.updateMemberProfileUrl(member, reqBodyForEditMemberProfileImage.file());
return ResponseEntity
.status(HttpStatus.OK)
.body(
new RsData<>(
"200",
"사용자의 프로필 이미지를 변경했습니다.",
new ResBodyForEditMemberProfileImage(member.getProfileImageUrl())
)
);
}

/**
* 현재 로그인한 사용자의 닉네임과 프로필 이미지를 변경하는 API
* HTTP METHOD: PUT
* @param userDetails @AuthenticationPrincipal로 받아오는 현재 사용자 정보
* @param reqBodyForEditMember 수정할 프로필 정보를 받아오는 dto
*/
@PutMapping("/edit")
@Operation(summary = "사용자 프로필 수정")
public ResponseEntity<RsData<ResBodyForEditMember>> editMemberProfile(
@AuthenticationPrincipal CustomUserDetails userDetails,
@Valid @RequestBody ReqBodyForEditMember reqBodyForEditMember
) {
Member member = userDetails.getMember();
memberService.updateMemberProfile(member, reqBodyForEditMember.newName(), reqBodyForEditMember.file());
return ResponseEntity
.status(HttpStatus.OK)
.body(
new RsData<>(
"200",
"사용자의 프로필을 변경했습니다.",
new ResBodyForEditMember(member.getName(), member.getProfileImageUrl())
)
);
}


/**
* 현재 로그인한 사용자를 삭제하는 API
* 사용할 지 모르겠음.
* HTTP METHOD: DELETE
* @param userDetails @AuthenticationPrincipal로 받아오는 현재 사용자 정보
*/

@DeleteMapping
@Operation(summary = "사용자 삭제")
public ResponseEntity<RsData<Void>> deleteMember(
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
package org.tuna.zoopzoop.backend.domain.member.dto.req;

import jakarta.validation.constraints.NotBlank;
import jakarta.validation.constraints.NotNull;
import org.springframework.web.multipart.MultipartFile;

public record ReqBodyForEditMember (
@NotBlank(message = "잘못된 요청입니다.") //MethodArgumentException
String newName,
@NotNull(message = "파일을 선택해주세요.")
MultipartFile file
) {
public ReqBodyForEditMember(String newName, MultipartFile file) {
this.newName = newName;
this.file = file;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
package org.tuna.zoopzoop.backend.domain.member.dto.req;

import jakarta.validation.constraints.NotNull;
import org.springframework.web.multipart.MultipartFile;

public record ReqBodyForEditMemberProfileImage (
@NotNull(message = "파일을 선택해주세요.")
MultipartFile file
) {
public ReqBodyForEditMemberProfileImage(MultipartFile file) {
this.file = file;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
package org.tuna.zoopzoop.backend.domain.member.dto.res;

public record ResBodyForEditMember(
String name,
String profileUrl
) {
public ResBodyForEditMember(String name, String profileUrl) {
this.name = name;
this.profileUrl = profileUrl;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
package org.tuna.zoopzoop.backend.domain.member.dto.res;

public record ResBodyForEditMemberProfileImage(
String profileUrl
) {
public ResBodyForEditMemberProfileImage(String profileUrl) {
this.profileUrl = profileUrl;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,18 +2,22 @@

import org.tuna.zoopzoop.backend.domain.member.entity.Member;

import java.time.LocalDateTime;

public record ResBodyForGetMemberInfoV2(
Integer id,
String name,
String profileUrl,
String provider
String provider,
LocalDateTime createAt
) {
public ResBodyForGetMemberInfoV2(Member member){
this(
member.getId(),
member.getName(),
member.getProfileImageUrl(),
member.getProvider().name()
member.getProvider().name(),
member.getCreateDate()
);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -54,9 +54,14 @@ public Member(String name, String providerKey, Provider provider, String profile

//---------- 메소드 ----------//
public boolean isActive() { return this.active; }
public void updateName(String name) { //사용자 이름 수정
public String updateName(String name) { //사용자 이름 수정
this.name = name;
return this.name;
} //사용자 이름 변경
public void deactivate() { this.active = false; } //soft-delete
public void activate() { this.active = true; } //restore
public String updateProfileUrl(String profileImageUrl) {
this.profileImageUrl = profileImageUrl;
return this.profileImageUrl;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -5,10 +5,14 @@
import org.springframework.dao.DataIntegrityViolationException;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.StringUtils;
import org.springframework.web.multipart.MultipartFile;
import org.tuna.zoopzoop.backend.domain.member.entity.Member;
import org.tuna.zoopzoop.backend.domain.member.enums.Provider;
import org.tuna.zoopzoop.backend.domain.member.repository.MemberRepository;
import org.tuna.zoopzoop.backend.global.aws.S3Service;

import java.io.IOException;
import java.util.List;
import java.util.Optional;
import java.util.UUID;
Expand All @@ -17,6 +21,7 @@
@RequiredArgsConstructor
public class MemberService {
private final MemberRepository memberRepository;
private final S3Service s3Service;

//회원 조회 관련
public Member findById(Integer id) {
Expand Down Expand Up @@ -84,8 +89,40 @@ public void updateMemberName(Member member, String newName){
throw new DataIntegrityViolationException("이미 사용중인 이름입니다.");
}
member.updateName(generateUniqueUserNameTag(newName));
memberRepository.save(member);
}

@Transactional
public void updateMemberProfileUrl(Member member, MultipartFile file){
String extension = StringUtils.getFilenameExtension(file.getOriginalFilename());
String fileName = "profile/" + member.getId() + "/profile." + extension;
try {
String newUrl = s3Service.upload(file, fileName);
member.updateProfileUrl(newUrl);
memberRepository.save(member);
} catch (IOException e) {
throw new IllegalArgumentException("잘못된 파일 입력입니다.");
}
}

@Transactional
public void updateMemberProfile(Member member, String newName, MultipartFile file){
if(memberRepository.findByName(newName).isPresent()) {
throw new DataIntegrityViolationException("이미 사용중인 이름입니다.");
}
member.updateName(generateUniqueUserNameTag(newName));
String extension = StringUtils.getFilenameExtension(file.getOriginalFilename());
String fileName = "profile/" + member.getId() + "/profile." + extension;
try {
String newUrl = s3Service.upload(file, fileName);
member.updateProfileUrl(newUrl);
memberRepository.save(member);
} catch (IOException e) {
throw new IllegalArgumentException("잘못된 파일 입력입니다.");
}
}


//회원 삭제/복구 관련
public void softDeleteMember(Member member){ member.deactivate(); }
public void hardDeleteMember(Member member){ memberRepository.delete(member); }
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
import org.tuna.zoopzoop.backend.domain.member.repository.MemberRepository;
import org.tuna.zoopzoop.backend.domain.member.service.MemberService;

import static org.hamcrest.Matchers.containsString;
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.*;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.jsonPath;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
Expand Down Expand Up @@ -158,21 +159,21 @@ void getMemberInfoByNameUnauthorized() throws Exception {
@DisplayName("사용자 이름 수정 - 성공(200)")
void editMemberNameSuccess() throws Exception {
ReqBodyForEditMemberName reqBodyForEditMemberName = new ReqBodyForEditMemberName("test3");
mockMvc.perform(put("/api/v1/member/edit")
mockMvc.perform(put("/api/v1/member/edit/name")
.contentType(MediaType.APPLICATION_JSON)
.content(objectMapper.writeValueAsString(reqBodyForEditMemberName)))
.andExpect(status().isOk())
.andExpect(jsonPath("$.status").value(200))
.andExpect(jsonPath("$.msg").value("사용자의 닉네임을 변경했습니다."))
.andExpect(jsonPath("$.data.name").value("test3"));
.andExpect(jsonPath("$.data.name").value(containsString("test")));
}

@Test
@WithUserDetails(value = "GOOGLE:2222", setupBefore = TestExecutionEvent.TEST_METHOD)
@DisplayName("사용자 이름 수정 - 실패(400, Bad_Request)")
void editMemberNameFailedByBadRequest() throws Exception {
ReqBodyForEditMemberName reqBodyForEditMemberName = new ReqBodyForEditMemberName("");
mockMvc.perform(put("/api/v1/member/edit")
mockMvc.perform(put("/api/v1/member/edit/name")
.contentType(MediaType.APPLICATION_JSON)
.content(objectMapper.writeValueAsString(reqBodyForEditMemberName)))
.andExpect(status().isBadRequest())
Expand All @@ -184,7 +185,7 @@ void editMemberNameFailedByBadRequest() throws Exception {
@DisplayName("사용자 이름 수정 - 실패(401, Unauthorized)")
void editMemberNameFailedByUnauthorized() throws Exception {
ReqBodyForEditMemberName reqBodyForEditMemberName = new ReqBodyForEditMemberName("test3");
mockMvc.perform(put("/api/v1/member/edit")
mockMvc.perform(put("/api/v1/member/edit/name")
.contentType(MediaType.APPLICATION_JSON)
.content(objectMapper.writeValueAsString(reqBodyForEditMemberName)))
.andExpect(status().isUnauthorized())
Expand Down