Skip to content

Commit

Permalink
Merge pull request #145 from team-offonoff/mypage
Browse files Browse the repository at this point in the history
feat: 마이페이지 API 추가
  • Loading branch information
60jong authored Jan 26, 2024
2 parents 7cdad2a + 2ef7db4 commit 1184985
Show file tree
Hide file tree
Showing 29 changed files with 885 additions and 42 deletions.
3 changes: 2 additions & 1 deletion src/docs/asciidoc/index.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -9,4 +9,5 @@ include::topic.adoc[]
include::oauth.adoc[]
include::auth.adoc[]
include::comment.adoc[]
include::image.adoc[]
include::image.adoc[]
include::member.adoc[]
77 changes: 77 additions & 0 deletions src/docs/asciidoc/member.adoc
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@

== 7. 멤버 API
### 7.1. 멤버 마이페이지 정보 수정

[source.html]
POST /members/profile/information

#### OK

operation::member-controller-test/update-members-profile-information_with-valid-field_success[snippets="http-request,http-response"]

#### E1. 닉네임에 한글, 영문, 숫자 외 문자 포함

operation::member-controller-test/update-members-profile-information_with-illegal-letter-nickname_exception[snippets="http-request,http-response"]

#### E2. 닉네임이 8자 초과

operation::member-controller-test/update-members-profile-information_with-long-nickname_exception[snippets="http-request,http-response"]

#### E3. 닉네임 중복

operation::member-controller-test/update-members-profile-information_with-duplicate-nickname_exception[snippets="http-request,http-response"]

#### E4. 직업에 한글, 영문, 숫자 외 문자 포함

닉네임일때 에러와 동일

### E5. 직업이 12자 초과

닉네임일때 에러와 동일

### 7.2 멤버의 프로필 이미지 변경

[source.html]
PUT members/profile/image

#### OK

operation::member-controller-test/update-members-profile-image[snippets="http-request,http-response"]

### 7.3 멤버의 프로필 이미지 삭제

[source.html]
DELETE members/profile/image

#### OK

operation::member-controller-test/remove-members-profile-image[snippets="http-request,http-response"]

### 7.4 멤버의 약관 동의 정보 조회

[source.html]
GET members/terms

#### OK

operation::member-controller-test/get-members-terms-agreement[snippets="http-request,http-response"]

### 7.5 멤버의 약관 동의 정보 수정

[source.html]
PUT members/terms

#### OK

operation::member-controller-test/update-members-terms-agreement[snippets="http-request,http-response"]

### 7.6 멤버 탈퇴

아직 복구는 고려하지 않음

[source.html]
PUT members/status

#### OK

operation::member-controller-test/update-members-status[snippets="http-request,http-response"]
16 changes: 12 additions & 4 deletions src/docs/asciidoc/oauth.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -11,20 +11,28 @@

### 2.1. authorize_code & redirect_uri

OK. 신규 회원
#### OK. 신규 회원

operation::o-auth-controller-test/oauth_kakao_new_member_by_code[snippets="request-fields,response-fields,http-request,http-response"]

OK. 기존 회원
#### OK. 기존 회원

operation::o-auth-controller-test/oauth_kakao_existing_member_by_code[snippets="http-request,http-response"]

#### E1. 탈퇴한 회원

operation::o-auth-controller-test/oauth_kakao_deactivated_member_by_code[snippets="http-request,http-response"]

### 2.2. id_token

OK. 신규 회원
#### OK. 신규 회원

operation::o-auth-controller-test/oauth_kakao_new_member_by_id-token[snippets="http-request,http-response"]

OK. 기존 회원
#### OK. 기존 회원

operation::o-auth-controller-test/oauth_kakao_existing_member_by_id-token[snippets="http-request,http-response"]

#### E1. 탈퇴한 회원

operation::o-auth-controller-test/oauth_kakao_deactivated_member_by_id-token[snippets="http-request,http-response"]
Original file line number Diff line number Diff line change
@@ -1,13 +1,18 @@
package life.offonoff.ab.application.service;

import life.offonoff.ab.exception.IllegalImageExtension;
import life.offonoff.ab.exception.S3InvalidFileUrlException;
import life.offonoff.ab.exception.S3InvalidKeyNameException;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import software.amazon.awssdk.auth.credentials.AwsBasicCredentials;
import software.amazon.awssdk.auth.credentials.AwsCredentialsProvider;
import software.amazon.awssdk.auth.credentials.StaticCredentialsProvider;
import software.amazon.awssdk.regions.Region;
import software.amazon.awssdk.services.s3.S3Client;
import software.amazon.awssdk.services.s3.model.DeleteObjectRequest;
import software.amazon.awssdk.services.s3.model.DeleteObjectResponse;
import software.amazon.awssdk.services.s3.model.PutObjectRequest;
import software.amazon.awssdk.services.s3.presigner.S3Presigner;
import software.amazon.awssdk.services.s3.presigner.model.PresignedPutObjectRequest;
Expand All @@ -28,7 +33,7 @@ public class S3Service {
private final String baseDir;
private final Pattern fileNamePattern =
Pattern.compile("(.*\\.(jpg|jpeg|png|gif|bmp))", Pattern.CASE_INSENSITIVE);

private final Pattern keynamePattern = Pattern.compile("^https://.+\\.s3\\..+\\.amazonaws.com/(.+)");
public S3Service(
@Value("${cloud.aws.credentials.access-key}") String accessKey,
@Value("${cloud.aws.credentials.secret-key}") String secretKey,
Expand Down Expand Up @@ -112,4 +117,45 @@ private URL createSignedUrlForImagePut(String keyName, String contentType) {
return presignedRequest.url();
}
}

public void deleteFile(String fileUrl) {
String keyName = getKeyNameFromFileUrl(fileUrl);
deleteObject(keyName);
}

private String getKeyNameFromFileUrl(String fileUrl) {
Matcher matcher = keynamePattern.matcher(fileUrl);
if (!matcher.matches()) {
log.warn("S3 파일 삭제 요청 URL이 올바르지 않습니다. | URL: {}", fileUrl);
throw new S3InvalidFileUrlException(fileUrl);
}
String keyName = matcher.group(1);
// 띄어쓰기 포함된 파일 이름의 경우 +를 띄어쓰기로 대체해줘야 삭제됨
return keyName.replace('+', ' ');
}

private void deleteObject(String keyName) {
try (S3Client s3 = S3Client.builder()
.region(Region.AP_NORTHEAST_2)
.credentialsProvider(credentialsProvider)
.build()) {

DeleteObjectRequest request = DeleteObjectRequest.builder()
.bucket(bucket)
.key(keyName)
.build();

DeleteObjectResponse response = s3.deleteObject(request);
boolean isSuccessful = response.sdkHttpResponse().isSuccessful();
if (!isSuccessful) {
// ! 주의할 것
// keyName이 존재해서 제대로 삭제되든,
// keyName이 틀려서 존재하지 않는 파일이어도 204 No Content 응답이 온다.
log.warn("keyName["+keyName+"] 삭제 실패 {} {}", response.sdkHttpResponse().statusCode(), response.sdkHttpResponse().statusText());
}
} catch (Exception e) {
log.warn("S3 삭제 요청 실패 [keyName={}]", keyName, e);
throw new S3InvalidKeyNameException(keyName);
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -6,19 +6,22 @@
import life.offonoff.ab.application.service.request.auth.SignInRequest;
import life.offonoff.ab.application.service.request.auth.SignUpRequest;
import life.offonoff.ab.domain.member.Member;
import life.offonoff.ab.exception.*;
import life.offonoff.ab.exception.DuplicateEmailException;
import life.offonoff.ab.exception.IllegalJoinStatusException;
import life.offonoff.ab.exception.IllegalPasswordException;
import life.offonoff.ab.exception.MemberByEmailNotFoundException;
import life.offonoff.ab.util.password.PasswordEncoder;
import life.offonoff.ab.util.token.TokenProvider;
import life.offonoff.ab.web.response.auth.join.JoinStatusResponse;
import life.offonoff.ab.web.response.auth.join.ProfileRegisterResponse;
import life.offonoff.ab.web.response.auth.join.SignUpResponse;
import life.offonoff.ab.web.response.auth.join.TermsResponse;
import life.offonoff.ab.web.response.auth.join.JoinTermsResponse;
import life.offonoff.ab.web.response.auth.login.SignInResponse;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import static life.offonoff.ab.domain.member.JoinStatus.*;
import static life.offonoff.ab.domain.member.JoinStatus.AUTH_REGISTERED;

@Transactional(readOnly = true)
@RequiredArgsConstructor
Expand Down Expand Up @@ -74,10 +77,10 @@ public JoinStatusResponse registerProfile(ProfileRegisterRequest request) {

private void beforeRegisterProfile(ProfileRegisterRequest request) {
final String nickname = request.getNickname();
memberService.checkMembersNickname(nickname);

if (memberService.existsByEmail(nickname)) {
throw new DuplicateNicknameException(nickname);
}
final String job = request.getJob();
memberService.checkMembersJob(job);
}

@Transactional
Expand All @@ -87,17 +90,17 @@ public JoinStatusResponse registerTerms(TermsRequest request) {
member.agreeTerms(request.toTermsEnabled());

Long memberId = member.getId();
return new TermsResponse(memberId,
member.getJoinStatus(),
tokenProvider.generateToken(memberId));
return new JoinTermsResponse(memberId,
member.getJoinStatus(),
tokenProvider.generateToken(memberId));
}

//== Sign In ==//
public SignInResponse signIn(SignInRequest request) {

beforeSignIn(request);

Member member = memberService.findByEmail(request.getEmail());
Member member = memberService.findMember(request.getEmail());

return new SignInResponse(member.getId(),
member.getJoinStatus(),
Expand All @@ -106,7 +109,7 @@ public SignInResponse signIn(SignInRequest request) {

private void beforeSignIn(SignInRequest request) {
String email = request.getEmail();
Member member = memberService.findByEmail(email);
Member member = memberService.findMember(email);

// email existence
if (!memberService.existsByEmail(email)) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,10 +6,10 @@
@Getter
@RequiredArgsConstructor
public enum LengthInfo {
// TODO: 댓글 최대 길이 요구사항대로 수정
COMMENT_CONTENT(1, 100),

PAGEABLE_SIZE(0, 100)
COMMENT_CONTENT(1, 255),
PAGEABLE_SIZE(0, 100),
NICKNAME_LENGTH(1, 8),
JOB_LENGTH(1, 12)
;

private final int minLength;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,9 @@
public class TextUtils {
private static final Pattern graphemePattern = Pattern.compile("\\X");

// 한글, 영문, 숫자
private static final Pattern specialCharacterFreePattern = Pattern.compile("^[0-9a-zA-Zㄱ-ㅎ가-힣]*$");

/*
* 이모티콘이 포함된 문자와 같이 2byte가 넘는 문자가 있을 경우 String의 길이는 우리가 인식하는 글자 단위보다 길어진다.
* 이 함수는 우리가 인식하는 대로 길이를 읽어온다.
Expand Down Expand Up @@ -36,4 +39,12 @@ public static int countEmojis(String text) {
public static int countGraphemeClustersWithLongerEmoji(String text) {
return countGraphemeClusters(text) + countEmojis(text);
}

/*
* 한글, 영문, 숫자
*/
public static boolean isOnlyKoreanEnglishNumberIncluded(String text) {
return specialCharacterFreePattern.matcher(text).matches();
}

}
Loading

0 comments on commit 1184985

Please sign in to comment.