Skip to content

Commit

Permalink
Merge pull request #530 from Travel-in-nanaland/feat/#495-join
Browse files Browse the repository at this point in the history
[feat] 회원 가입 수정
  • Loading branch information
jyajoo authored Dec 11, 2024
2 parents d1257a5 + 71255c1 commit 767b1d3
Show file tree
Hide file tree
Showing 6 changed files with 43 additions and 53 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -42,17 +42,14 @@
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.http.HttpHeaders;
import org.springframework.http.MediaType;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PatchMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestHeader;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RequestPart;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.multipart.MultipartFile;

@Slf4j
@RestController
Expand All @@ -75,12 +72,11 @@ public class MemberController {
@ApiResponse(responseCode = "409", description = "이미 가입된 계정이 있는 경우, 닉네임이 중복되는 경우", content = @Content),
@ApiResponse(responseCode = "500", description = "서버측 에러", content = @Content)
})
@PostMapping(value = "/join",
consumes = MediaType.MULTIPART_FORM_DATA_VALUE, produces = MediaType.APPLICATION_JSON_VALUE)
@PostMapping(value = "/join")
public BaseResponse<JwtDto> join(
@RequestPart(value = "reqDto") @Valid MemberRequest.JoinDto joinDto,
@RequestPart(required = false) MultipartFile multipartFile) {
JwtDto jwtDto = memberLoginService.join(joinDto, multipartFile);
@RequestBody @Valid MemberRequest.JoinDto joinDto,
@RequestParam(required = false) String fileKey) {
JwtDto jwtDto = memberLoginService.join(joinDto, fileKey);
return BaseResponse.success(JOIN_SUCCESS, jwtDto);
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,6 @@
import com.jeju.nanaland.domain.common.data.Language;
import com.jeju.nanaland.domain.common.data.Status;
import com.jeju.nanaland.domain.common.entity.ImageFile;
import com.jeju.nanaland.domain.common.service.FileService;
import com.jeju.nanaland.domain.common.service.ImageFileService;
import com.jeju.nanaland.domain.member.dto.MemberRequest;
import com.jeju.nanaland.domain.member.dto.MemberResponse.MemberInfoDto;
Expand All @@ -26,8 +25,10 @@
import com.jeju.nanaland.global.exception.ConflictException;
import com.jeju.nanaland.global.exception.NotFoundException;
import com.jeju.nanaland.global.exception.UnauthorizedException;
import com.jeju.nanaland.global.file.data.FileCategory;
import com.jeju.nanaland.global.file.service.FileUploadService;
import com.jeju.nanaland.global.image_upload.dto.S3ImageDto;
import com.jeju.nanaland.global.util.JwtUtil;
import java.io.File;
import java.util.List;
import java.util.Optional;
import java.util.UUID;
Expand All @@ -36,7 +37,6 @@
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.multipart.MultipartFile;

@Service
@RequiredArgsConstructor
Expand All @@ -49,19 +49,19 @@ public class MemberLoginService {
private final MemberConsentService memberConsentService;
private final ImageFileService imageFileService;
private final FcmTokenService fcmTokenService;
private final FileService fileService;
private final MemberProfileService memberProfileService;
private final FileUploadService fileUploadService;

/**
* 회원 가입
*
* @param joinDto 회원 가입 정보
* @param multipartFile 프로필 사진
* @param joinDto 회원 가입 정보
* @param fileKey 파일 키
* @return JWT
* @throws ConflictException provider, providerId로 이미 가입된 회원이 존재하는 경우
*/
@Transactional
public JwtDto join(MemberRequest.JoinDto joinDto, MultipartFile multipartFile) {
public JwtDto join(MemberRequest.JoinDto joinDto, String fileKey) {
Optional<Member> savedMember = memberRepository.findByProviderAndProviderId(
Provider.valueOf(joinDto.getProvider()),
joinDto.getProviderId());
Expand All @@ -73,7 +73,7 @@ public JwtDto join(MemberRequest.JoinDto joinDto, MultipartFile multipartFile) {

String nickname = determineNickname(joinDto);
validateNickname(nickname);
ImageFile profileImageFile = memberProfileService.saveRandomProfileImageFile();
ImageFile profileImageFile = createProfileImageFile(fileKey);
Member member = createMember(joinDto, profileImageFile, nickname);

// GUEST가 아닌 경우, 이용약관 저장
Expand All @@ -86,15 +86,26 @@ public JwtDto join(MemberRequest.JoinDto joinDto, MultipartFile multipartFile) {
fcmTokenService.createFcmToken(member, joinDto.getFcmToken());
}

// 비동기 처리
if (multipartFile != null && !multipartFile.isEmpty()) {
File convertedFile = fileService.convertMultipartFileToFile(multipartFile);
imageFileService.uploadMemberProfileImage(member.getId(), convertedFile);
}

return getJwtDto(member);
}

/**
* 프로필 사진 업로드 및 저장.
* 프로필 사진이 없는 경우엔, 랜덤 프로필 사진 저장
*
* @param fileKey 파일 키
* @return 저장된 이미지 파일 또는 랜덤 프로필 사진 파일
*/
private ImageFile createProfileImageFile(String fileKey) {
if (fileKey == null) {
return memberProfileService.saveRandomProfileImageFile();
}
fileUploadService.validateFileExtension(fileKey, FileCategory.MEMBER_PROFILE);
S3ImageDto s3ImageDto = fileUploadService.getCloudImageUrls(fileKey);
return imageFileService.saveS3ImageFile(s3ImageDto);
}


/**
* 닉네임 설정. GUEST 유형의 경우 UUID를 사용하여 랜덤 닉네임 생성. GUEST가 아닌 경우, 제공된 닉네임을 반환.
*
Expand Down Expand Up @@ -202,7 +213,6 @@ private JwtDto getJwtDto(Member member) {
* @param member 회원
* @throws NotFoundException 존재하는 회원 탈퇴 정보가 없는 경우
*/
@Transactional
public void updateMemberActive(Member member) {
if (member.getStatus().equals(Status.INACTIVE)) {
member.updateStatus(Status.ACTIVE);
Expand All @@ -219,7 +229,6 @@ public void updateMemberActive(Member member) {
* @param loginDto 로그인 정보
* @param member 회원
*/
@Transactional
public void updateLanguageDifferent(MemberRequest.LoginDto loginDto, Member member) {
Language language = Language.valueOf(loginDto.getLocale());
if (!member.getLanguage().equals(language)) {
Expand Down Expand Up @@ -316,7 +325,6 @@ public void withdrawal(MemberInfoDto memberInfoDto, MemberRequest.WithdrawalDto
/**
* 매일 0시 0분 0초에 실행되는 회원 탈퇴 스케줄러. 비활성화 후 3개월이 지난 회원 탈퇴 처리
*/
@Transactional
@Scheduled(cron = "0 0 0 * * *")
public void deleteWithdrawalMemberInfo() {
List<Member> members = memberRepository.findAllInactiveMember();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,6 @@ public enum ErrorCode {
SELF_REPORT_NOT_ALLOWED(BAD_REQUEST, "본인을 신고하는 요청은 유효하지 않습니다."),
ALREADY_REPORTED(BAD_REQUEST, "이미 신고되었습니다."),
NO_NOTIFICATION_CONSENT(BAD_REQUEST, "알림 동의를 하지 않은 유저입니다."),
INVALID_FILE_SIZE(BAD_REQUEST, "파일 크기가 유효하지 않습니다."),
INVALID_FILE_EXTENSION_TYPE(BAD_REQUEST, "해당 카테고리에서 지원하지 않는 파일 형식입니다."),
NO_FILE_EXTENSION(BAD_REQUEST, "파일 확장자가 없습니다."),

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@
import com.jeju.nanaland.domain.common.annotation.EnumValid;
import com.jeju.nanaland.global.file.data.FileCategory;
import io.swagger.v3.oas.annotations.media.Schema;
import jakarta.validation.constraints.Max;
import jakarta.validation.constraints.Min;
import jakarta.validation.constraints.NotBlank;
import jakarta.validation.constraints.NotEmpty;
import jakarta.validation.constraints.NotNull;
Expand All @@ -23,10 +25,12 @@ public static class InitCommandDto {

@NotNull
@Schema(description = "파일 크기")
@Max(30 * 1024 * 1024)
private Long fileSize;

@NotNull
@Schema(description = "파일 파트 개수")
@Min(1)
private int partCount;

@EnumValid(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@
import static com.jeju.nanaland.global.exception.ErrorCode.FILE_S3_NOT_FOUNE;
import static com.jeju.nanaland.global.exception.ErrorCode.FILE_UPLOAD_FAIL;
import static com.jeju.nanaland.global.exception.ErrorCode.INVALID_FILE_EXTENSION_TYPE;
import static com.jeju.nanaland.global.exception.ErrorCode.INVALID_FILE_SIZE;
import static com.jeju.nanaland.global.exception.ErrorCode.NO_FILE_EXTENSION;

import com.amazonaws.HttpMethod;
Expand All @@ -29,7 +28,6 @@
import com.jeju.nanaland.global.image_upload.dto.S3VideoDto;
import jakarta.validation.Valid;
import jakarta.validation.constraints.NotBlank;
import jakarta.validation.constraints.NotNull;
import java.net.URL;
import java.time.LocalDate;
import java.time.LocalDateTime;
Expand All @@ -51,7 +49,6 @@ public class FileUploadService {

private static final int MAX_IMAGE_COUNT = 5;
private static final int PRESIGNEDURL_EXPIRATION = 30;
private static final long MAX_FILE_SIZE = 30 * 1024 * 1024L;
private final AmazonS3 amazonS3;
private final AmazonS3Client amazonS3Client;
@Value("${cloud.aws.cloudfront.domain}")
Expand All @@ -68,9 +65,6 @@ public class FileUploadService {
private String claimReportDirectory;

public FileResponse.InitResultDto uploadInit(FileRequest.InitCommandDto initCommandDto) {
// 파일 크기 유효성 검사
validateFileSize(initCommandDto.getFileSize());

// 파일 형식 유효성 검사
String contentType = validateFileExtension(initCommandDto.getOriginalFileName(),
FileCategory.valueOf(initCommandDto.getFileCategory()));
Expand Down Expand Up @@ -121,12 +115,6 @@ public FileResponse.InitResultDto uploadInit(FileRequest.InitCommandDto initComm
}
}

private void validateFileSize(@NotNull Long fileSize) {
if (fileSize > MAX_FILE_SIZE) {
throw new BadRequestException(INVALID_FILE_SIZE.getMessage());
}
}

/**
* 파일 확장자 유효성 확인
*
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
import com.jeju.nanaland.domain.common.data.Language;
import com.jeju.nanaland.domain.common.data.Status;
import com.jeju.nanaland.domain.common.entity.ImageFile;
import com.jeju.nanaland.domain.common.service.ImageFileService;
import com.jeju.nanaland.domain.member.dto.MemberRequest;
import com.jeju.nanaland.domain.member.dto.MemberRequest.JoinDto;
import com.jeju.nanaland.domain.member.dto.MemberResponse.MemberInfoDto;
Expand All @@ -32,6 +33,7 @@
import com.jeju.nanaland.global.exception.ErrorCode;
import com.jeju.nanaland.global.exception.NotFoundException;
import com.jeju.nanaland.global.exception.UnauthorizedException;
import com.jeju.nanaland.global.file.service.FileUploadService;
import com.jeju.nanaland.global.util.JwtUtil;
import java.time.LocalDate;
import java.util.ArrayList;
Expand All @@ -47,8 +49,6 @@
import org.mockito.InjectMocks;
import org.mockito.Mock;
import org.mockito.junit.jupiter.MockitoExtension;
import org.springframework.mock.web.MockMultipartFile;
import org.springframework.web.multipart.MultipartFile;


@ExtendWith(MockitoExtension.class)
Expand All @@ -71,6 +71,10 @@ class MemberLoginServiceTest {
private FcmTokenService fcmTokenService;
@Mock
private MemberProfileService memberProfileService;
@Mock
private FileUploadService fileUploadService;
@Mock
private ImageFileService imageFileService;
@InjectMocks
private MemberLoginService memberLoginService;

Expand Down Expand Up @@ -243,26 +247,22 @@ void joinSuccess_multipartFileExists() {
// given: 프로필 사진이 있는 경우
Language language = Language.KOREAN;
Member member = createMember(language, joinDto);
MultipartFile multipartFile = new MockMultipartFile("file", "test.jpg", "image/jpeg",
new byte[0]);
String fileKey = "test/1.png";
doReturn(Optional.empty())
.when(memberRepository).findByProviderAndProviderId(any(Provider.class), any(String.class));
doReturn(Optional.empty()).when(memberRepository).findByNickname(any(String.class));
doReturn(imageFile).when(memberProfileService).saveRandomProfileImageFile();
doReturn(member).when(memberRepository).save(any(Member.class));
doReturn("accessToken").when(jwtUtil).createAccessToken(any(String.class), anySet());
doReturn("refreshToken").when(jwtUtil).createRefreshToken(any(String.class), anySet());

// when: 회원 가입
JwtDto result = memberLoginService.join(joinDto, multipartFile);
JwtDto result = memberLoginService.join(joinDto, fileKey);

// then: JWT 생성 확인, 이용약관 생성 확인, 프로필 사진 확인
assertThat(result).isNotNull();
assertThat(result.getAccessToken()).isEqualTo("accessToken");
assertThat(result.getRefreshToken()).isEqualTo("refreshToken");
verify(memberConsentService).createMemberConsents(any(Member.class), anyList());
verify(memberRepository).save(argThat(savedMember ->
savedMember.getProfileImageFile().equals(imageFile)));
}

@Test
Expand All @@ -273,27 +273,22 @@ void joinSuccess_fcmTokenExists(){
JoinDto joinDto2 = createJoinDto("GOOGLE");
joinDto2.setFcmToken("fcmToken");
Member member = createMember(language, joinDto2);
MultipartFile multipartFile = new MockMultipartFile("file", "test.jpg", "image/jpeg",
new byte[0]);
doReturn(Optional.empty())
.when(memberRepository).findByProviderAndProviderId(any(Provider.class), any(String.class));
doReturn(Optional.empty()).when(memberRepository).findByNickname(any(String.class));
doReturn(imageFile).when(memberProfileService).saveRandomProfileImageFile();
doReturn(member).when(memberRepository).save(any(Member.class));
doReturn("accessToken").when(jwtUtil).createAccessToken(any(String.class), anySet());
doReturn("refreshToken").when(jwtUtil).createRefreshToken(any(String.class), anySet());

// when: 회원 가입
JwtDto result = memberLoginService.join(joinDto2, multipartFile);
JwtDto result = memberLoginService.join(joinDto2, null);

// then: JWT 생성 확인, 이용약관 생성 확인, fcmToken 생성 확인, 프로필 사진 확인
// then: JWT 생성 확인, 이용약관 생성 확인, fcmToken 생성 확인
assertThat(result).isNotNull();
assertThat(result.getAccessToken()).isEqualTo("accessToken");
assertThat(result.getRefreshToken()).isEqualTo("refreshToken");
verify(memberConsentService).createMemberConsents(any(Member.class), anyList());
verify(fcmTokenService).createFcmToken(any(Member.class), any(String.class));
verify(memberRepository).save(argThat(savedMember ->
savedMember.getProfileImageFile().equals(imageFile)));
}
}

Expand Down

0 comments on commit 767b1d3

Please sign in to comment.