Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[feat] 회원가입 및 프로필 수정 스펙 변경 #256

Merged
merged 6 commits into from
Mar 5, 2024
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
27 changes: 27 additions & 0 deletions src/docs/asciidoc/api/member.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -51,3 +51,30 @@ include::{snippets}/member-delete/request-fields.adoc[]

include::{snippets}/member-delete/http-response.adoc[]
include::{snippets}/member-delete/response-fields.adoc[]

[[member-signup]]
=== 일반 회원가입

==== HTTP Request

include::{snippets}/member-signup/http-request.adoc[]
include::{snippets}/member-signup/request-parts.adoc[]

==== HTTP Response

include::{snippets}/member-signup/http-response.adoc[]
include::{snippets}/member-signup/response-fields.adoc[]

[[member-update]]
=== 회원 프로필 수정

==== HTTP Request

include::{snippets}/member-update/http-request.adoc[]
include::{snippets}/member-update/request-headers.adoc[]
include::{snippets}/member-update/request-parts.adoc[]

==== HTTP Response

include::{snippets}/member-update/http-response.adoc[]
include::{snippets}/member-update/response-fields.adoc[]
14 changes: 7 additions & 7 deletions src/docs/asciidoc/index.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -10,30 +10,30 @@ endif::[]
:sectlinks:

[[Product-API]]
== 회원 API
== 회원

include::api/member.adoc[]

== 포트폴리오 API
== 포트폴리오

include::api/portfolio.adoc[]

== 포트폴리오 종목 API
== 포트폴리오 종목

include::api/holding.adoc[]

== FCM 토큰 API
== FCM 토큰

include::api/fcm.adoc[]

== 종목 지정가 알림 API
== 종목 지정가 알림

include::api/stock_target_price.adoc[]

== 알림 API
== 알림

include::api/notification.adoc[]

== 대시보드 API
== 대시보드

include::api/dashboard.adoc[]
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,10 @@
public interface MemberRepository extends JpaRepository<Member, Long> {
Optional<Member> findMemberByEmailAndProvider(String email, String provider);

@Query("select m from Member m where m.nickname = :nickname and m.id != :memberId")
Optional<Member> findMemberByNicknameAndNotMemberId(@Param("nickname") String nickname,
@Param("memberId") Long memberId);

boolean existsMemberByEmailAndProvider(String email, String provider);

boolean existsByNickname(String nickname);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.multipart.MultipartFile;

import com.amazonaws.AmazonServiceException;
import com.amazonaws.services.s3.AmazonS3;
import com.amazonaws.services.s3.model.CannedAccessControlList;
import com.amazonaws.services.s3.model.PutObjectRequest;
Expand Down Expand Up @@ -58,4 +59,20 @@ private Optional<File> convertMultiPartFileToFile(MultipartFile file) {

return Optional.of(convertedFile);
}

public void deleteFile(String url) {
try {
String fileName = extractFileName(url);
amazonS3.deleteObject(bucketName, fileName);
} catch (AmazonServiceException e) {
log.error(e.getMessage());
}
}

// URL에서 파일 이름 추출하는 메소드
private String extractFileName(String url) {
// 예시: https://fineants.s3.ap-northeast-2.amazonaws.com/9d07ee41-4404-414b-9ee7-12616aa6bedcprofile.jpeg
int lastSlashIndex = url.lastIndexOf('/');
return url.substring(lastSlashIndex + 1);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,8 @@ public enum MemberErrorCode implements ErrorCode {
IMAGE_SIZE_EXCEEDED(HttpStatus.BAD_REQUEST, "이미지 사이즈 제한을 초과했습니다."),
LOGIN_FAIL(HttpStatus.BAD_REQUEST, "로그인에 실패하였습니다."),
FORBIDDEN_MEMBER(HttpStatus.FORBIDDEN, "권한이 없습니다."),
NO_PROFILE_CHANGES(HttpStatus.BAD_REQUEST, "변경할 회원 정보가 없습니다");
NO_PROFILE_CHANGES(HttpStatus.BAD_REQUEST, "변경할 회원 정보가 없습니다"),
BAD_REQUEST_PROFILE_URL(HttpStatus.BAD_REQUEST, "회원의 프로필 URL과 요청 프로필 URL이 일치하지 않습니다");

private final HttpStatus httpStatus;
private final String message;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -126,13 +126,16 @@ public ApiResponse<LoginResponse> login(@RequestBody final LoginRequest request)
return ApiResponse.success(MemberSuccessCode.OK_LOGIN, memberService.login(request));
}

@PutMapping(value = "/profile", consumes = {MediaType.MULTIPART_FORM_DATA_VALUE, MediaType.APPLICATION_JSON_VALUE})
@PostMapping(value = "/profile", consumes = {MediaType.MULTIPART_FORM_DATA_VALUE, MediaType.APPLICATION_JSON_VALUE})
public ApiResponse<ProfileChangeResponse> changeProfile(
@RequestPart(value = "profileImageFile", required = false) MultipartFile profileImageFile,
@Valid @RequestPart(value = "profileInformation", required = false) ProfileChangeRequest request,
@AuthPrincipalMember AuthMember authMember) {
ProfileChangeServiceRequest serviceRequest = new ProfileChangeServiceRequest(profileImageFile,
request, authMember);
ProfileChangeServiceRequest serviceRequest = ProfileChangeServiceRequest.of(
profileImageFile,
request,
authMember.getMemberId()
);
return ApiResponse.success(MemberSuccessCode.OK_MODIFIED_PROFILE,
memberService.changeProfile(serviceRequest));
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,6 @@
import codesquad.fineants.spring.api.member.request.OauthMemberLoginRequest;
import codesquad.fineants.spring.api.member.request.OauthMemberLogoutRequest;
import codesquad.fineants.spring.api.member.request.OauthMemberRefreshRequest;
import codesquad.fineants.spring.api.member.request.ProfileChangeRequest;
import codesquad.fineants.spring.api.member.request.VerifyCodeRequest;
import codesquad.fineants.spring.api.member.request.VerifyEmailRequest;
import codesquad.fineants.spring.api.member.response.LoginResponse;
Expand Down Expand Up @@ -226,7 +225,11 @@ public SignUpServiceResponse signup(SignUpServiceRequest request) {
verifyPassword(request.getPassword(), request.getPasswordConfirm());

// 프로필 이미지 파일 S3에 업로드
String profileUrl = uploadProfileImageFile(request.getProfileImageFile());
String profileUrl = null;
if (request.getProfileImageFile() != null && !request.getProfileImageFile().isEmpty()) {
profileUrl = uploadProfileImageFile(request.getProfileImageFile());
}

// 비밀번호 암호화
String encryptedPassword = encryptPassword(request.getPassword());
// 회원 데이터베이스 저장
Expand Down Expand Up @@ -260,7 +263,14 @@ private void verifyEmail(String email) {

private void verifyNickname(String nickname) {
if (memberRepository.existsByNickname(nickname)) {
throw new BadRequestException(MemberErrorCode.REDUNDANT_NICKNAME);
throw new FineAntsException(MemberErrorCode.REDUNDANT_NICKNAME);
}
}

// memberId을 제외한 다른 nickname이 존재하는지 검증
private void verifyNickname(String nickname, Long memberId) {
if (memberRepository.findMemberByNicknameAndNotMemberId(nickname, memberId).isPresent()) {
throw new FineAntsException(MemberErrorCode.REDUNDANT_NICKNAME);
}
}

Expand Down Expand Up @@ -315,40 +325,51 @@ public LoginResponse login(LoginRequest request) {
}

@Transactional
public ProfileChangeResponse changeProfile(ProfileChangeServiceRequest serviceRequest) {
verifyNoProfileChanges(serviceRequest);
Member member = findMemberById(serviceRequest.getMemberId());
extractMemberProfileImage(serviceRequest)
.map(amazonS3Service::upload)
.ifPresent(member::updateProfileUrl);
extractNickname(serviceRequest)
.ifPresent(member::updateNickname);
return ProfileChangeResponse.from(member);
}

private void verifyNoProfileChanges(ProfileChangeServiceRequest serviceRequest) {
if (serviceRequest.getProfileImageFile().isEmpty() && serviceRequest.getRequest().isEmpty()) {
throw new BadRequestException(MemberErrorCode.NO_PROFILE_CHANGES);
public ProfileChangeResponse changeProfile(ProfileChangeServiceRequest request) {
Member member = findMemberById(request.getMemberId());
MultipartFile profileImageFile = request.getProfileImageFile();
String profileUrl = null;

// 변경할 정보가 없는 경우
if (profileImageFile == null && request.getNickname().isBlank()) {
throw new FineAntsException(MemberErrorCode.NO_PROFILE_CHANGES);
}
}

private Member findMemberById(Optional<Long> optionalMemberId) {
return optionalMemberId
.flatMap(memberRepository::findById)
.orElseThrow(() -> new BadRequestException(MemberErrorCode.NOT_FOUND_MEMBER));
}
// 기존 프로필 파일 유지
if (profileImageFile == null) {
profileUrl = member.getProfileUrl();
}
// 기본 프로필 파일로 변경인 경우
else if (profileImageFile.isEmpty()) {
// 회원의 기존 프로필 사진 제거
// 기존 프로필 파일 삭제
if (member.getProfileUrl() != null) {
amazonS3Service.deleteFile(member.getProfileUrl());
}
}
// 새로운 프로필 파일로 변경인 경우
else if (!profileImageFile.isEmpty()) {
// 기존 프로필 파일 삭제
if (member.getProfileUrl() != null) {
amazonS3Service.deleteFile(member.getProfileUrl());
}

// 새로운 프로필 파일 저장
profileUrl = amazonS3Service.upload(profileImageFile);
}
member.updateProfileUrl(profileUrl);

private Optional<MultipartFile> extractMemberProfileImage(ProfileChangeServiceRequest serviceRequest) {
return serviceRequest.getProfileImageFile();
if (!request.getNickname().isBlank()) {
String nickname = request.getNickname();
verifyNickname(nickname, member.getId());
member.updateNickname(nickname);
}
return ProfileChangeResponse.from(member);
}

private Optional<String> extractNickname(ProfileChangeServiceRequest serviceRequest) {
return serviceRequest.getRequest()
.map(ProfileChangeRequest::getNickname)
.map(nickname -> {
verifyNickname(nickname);
return nickname;
});
private Member findMemberById(Long memberId) {
return memberRepository.findById(memberId)
.orElseThrow(() -> new FineAntsException(MemberErrorCode.NOT_FOUND_MEMBER));
}

@Transactional
Expand Down
Original file line number Diff line number Diff line change
@@ -1,23 +1,27 @@
package codesquad.fineants.spring.api.member.service.request;

import java.util.Optional;

import org.apache.logging.log4j.util.Strings;
import org.springframework.web.multipart.MultipartFile;

import codesquad.fineants.domain.oauth.support.AuthMember;
import codesquad.fineants.spring.api.member.request.ProfileChangeRequest;
import lombok.AccessLevel;
import lombok.AllArgsConstructor;
import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.ToString;

@Getter
@NoArgsConstructor(access = AccessLevel.PRIVATE)
@AllArgsConstructor(access = AccessLevel.PRIVATE)
@ToString
public class ProfileChangeServiceRequest {
private final Optional<MultipartFile> profileImageFile;
private final Optional<ProfileChangeRequest> request;
private final Optional<Long> memberId;
private MultipartFile profileImageFile;
private String nickname;
private Long memberId;

public ProfileChangeServiceRequest(MultipartFile profileImageFile, ProfileChangeRequest request,
AuthMember authMember) {
this.profileImageFile = Optional.ofNullable(profileImageFile);
this.request = Optional.ofNullable(request);
this.memberId = Optional.of(authMember.getMemberId());
public static ProfileChangeServiceRequest of(MultipartFile profileImageFile, ProfileChangeRequest request,
Long memberId) {
String nickname = request != null ? request.getNickname() : Strings.EMPTY;
return new ProfileChangeServiceRequest(profileImageFile, nickname, memberId);
}
}
11 changes: 8 additions & 3 deletions src/main/resources/stocks.tsv
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,6 @@ KR7353810005 353810 이지바이오 EASY BIO, Inc. KOSDAQ
KR7029960002 029960 코엔텍 Korea Environment Technology Co., LTD. KOSDAQ
KR7060590007 060590 씨티씨바이오 CTC BIO, INC. KOSDAQ
KR7403490006 403490 농업회사법인 우듬지팜 WooDeumGee Farm Co., Ltd KOSDAQ
KR7204210009 204210 모두투어리츠보통주 MODETOURREIT KOSPI
KR7291810000 291810 핀텔 Pintel Co., Ltd. KOSDAQ
KR7008250003 008250 이건산업보통주 EagonIndustrial KOSPI
KR7378850002 378850 화승알앤에이보통주 HWASEUNG R&A CO., LTD. KOSPI
Expand All @@ -78,6 +77,7 @@ KR7040610008 040610 에스지엔지 SG&G Corporation KOSDAQ
KR7021240007 021240 코웨이보통주 COWAY KOSPI
KR7039420005 039420 케이엘넷 KL-Net Corp. KOSDAQ
KR7123570004 123570 이엠넷 EMNET INC. KOSDAQ
KR7360350003 360350 코셈 COXEM CO.,LTD KOSDAQ
KR7454750001 454750 하나28호기업인수목적 Hana 28 Special Purpose Acquisition Company KOSDAQ
KR7200880003 200880 서연이화보통주 SEOYONEHWA KOSPI
KR7194480000 194480 데브시스터즈 Devsisters corporation KOSDAQ
Expand Down Expand Up @@ -260,7 +260,6 @@ KR7339770000 339770 교촌에프앤비보통주 KYOCHON FOOD&BEVERAGE KOSPI
KR7133750000 133750 메가엠디 MegaMD Co., Ltd. KOSDAQ
KR7090150004 090150 아이윈 iWIN KOSDAQ
KR7193250008 193250 와이제이엠게임즈 YJM Games Co., Ltd. KOSDAQ
KR7001880004 001880 DL건설보통주 DLConstruction KOSPI
KR7004960001 004960 한신공영보통주 HanshinConstruction KOSPI
KR7097800007 097800 윈팩 WINPAC INC. KOSDAQ
KR7002030005 002030 아세아보통주 ASIA HOLDINGS KOSPI
Expand Down Expand Up @@ -639,6 +638,7 @@ KR7257990002 257990 나우코스 NOWCOS KONEX
KR7194370003 194370 제이에스코퍼레이션보통주 JS Corporation KOSPI
KR7277880001 277880 티에스아이 TSI Co., Ltd. KOSDAQ
KR7120110002 120110 코오롱인더스트리보통주 KOLON INDUSTRIES KOSPI
KR7418620001 418620 이에이트 E8IGHT Co., Ltd KOSDAQ
KR7086060001 086060 진바이오텍 Gene Bio Tech Co., Ltd. KOSDAQ
KR7377030002 377030 맥스트 MAXST CO., LTD KOSDAQ
KR7078160009 078160 메디포스트 MEDIPOST CO., LTD. KOSDAQ
Expand Down Expand Up @@ -838,7 +838,6 @@ KR7021880000 021880 메이슨캐피탈 MASON CAPITAL CORPORATION KOSDAQ
KR7372320002 372320 큐로셀 Curocell Inc. KOSDAQ
KR7215570003 215570 크로넥스 CRONEX KONEX
KR7058730003 058730 다스코보통주 Development Advance Solution KOSPI
KR7039980008 039980 리노스 LEENOS CORP. KOSDAQ
KR7020150009 020150 롯데에너지머티리얼즈보통주 LOTTE ENERGY MATERIALS CORPORATION KOSPI
KR7103590006 103590 일진전기 보통주 ILJIN ELECTRIC KOSPI
KR7154030001 154030 농업회사법인 아시아종묘 ASIA SEED Co.,Ltd. KOSDAQ
Expand Down Expand Up @@ -1382,6 +1381,7 @@ KR7236810008 236810 엔비티 NBT INC. KOSDAQ
KR7347700007 347700 라이프시맨틱스 Life Semantics Corp. KOSDAQ
KR7000050005 000050 경방보통주 Kyungbang KOSPI
KR7007860000 007860 서연보통주 SEOYON KOSPI
KR7204210009 204210 스타자기관리부동산투자회사보통주 STAR Real Estate Investment Trust Incorporated KOSPI
KR7262260003 262260 에이프로 A PRO Co., LTD KOSDAQ
KR7303530000 303530 이노뎁 INNODEP INC. KOSDAQ
KR7180400004 180400 디엑스앤브이엑스 Dx & Vx KOSDAQ
Expand Down Expand Up @@ -1880,6 +1880,7 @@ KR7006401004 006405 삼성SDI1우선주 SAMSUNG SDI(1P) KOSPI
KR7042600007 042600 새로닉스 SERONICS. CO., LTD. KOSDAQ
KR7271830002 271830 팸텍 PAMTEK CO., LTD. KOSDAQ
KR7068240001 068240 다원시스 DAWONSYS Co., LTD KOSDAQ
KR7473050003 473050 유안타제15호기업인수목적 Yuanta 15 SPECIAL PURPOSE ACQUISITION COMPANY KOSDAQ
KR7053260006 053260 금강철강 KEUM KANG STEEL CO., LTD KOSDAQ
KR7041510009 041510 에스엠엔터테인먼트 SM ENTERTAINMENT CO., Ltd. KOSDAQ
KR7068790005 068790 디엠에스 DMS Co.,Ltd. KOSDAQ
Expand Down Expand Up @@ -2211,6 +2212,7 @@ KR7446150005 446150 유안타제12호기업인수목적 Yuanta 12 SPECIAL PURPOS
KR7036420008 036420 콘텐트리중앙보통주 ContentreeJoongAng corp. KOSPI
KR7001530005 001530 DI동일보통주 DI DONGIL KOSPI
KR7196700009 196700 웹스 WAPS Co., Ltd. KOSDAQ
KR7039980008 039980 폴라리스에이아이 Polaris AI KOSDAQ
KR7181710005 181710 NHN보통주 NHN KOSPI
KR7255220006 255220 에스지이 SG CO., LTD. KOSDAQ
KR7023770001 023770 플레이위드코리아 PLAYWITH KOREA KOSDAQ
Expand All @@ -2229,6 +2231,7 @@ KR7001800002 001800 오리온홀딩스보통주 ORION Holdings KOSPI
KR7003240009 003240 태광산업보통주 TaekwangIndustrial KOSPI
KR7053950002 053950 경남제약 KYUNG NAM PHARM.CO.,LTD. KOSDAQ
KR7088290002 088290 이원컴포텍 EWON COMFORTECH CO., LTD KOSDAQ
KR7278470000 278470 에이피알보통주 APR KOSPI
KR7103140000 103140 풍산 보통주 POONGSAN CORPORATION KOSPI
KR7256840000 256840 한국비엔씨 BNC Korea Co, Ltd KOSDAQ
KR7307180000 307180 아이엘사이언스 IL SCIENCE CO.,LTD. KOSDAQ
Expand Down Expand Up @@ -2687,6 +2690,7 @@ KR7106190002 106190 하이텍팜 HIGH TECH PHARM CO., LTD. KOSDAQ
KR7074610007 074610 이엔플러스보통주 ENPLUS KOSPI
KR7238090005 238090 앤디포스 NDFOS Co., Ltd. KOSDAQ
KR7048770002 048770 티피씨메카트로닉스 TPC Mechatronics Corporation KOSDAQ
KR7472230002 472230 에스케이증권제11호기업인수목적 SK Securities No.11 Special Purpose Acquisition Company KOSDAQ
KR7003010006 003010 혜인보통주 HaeinCorporation KOSPI
KR7049830003 049830 승일 SEUNG IL Corporation KOSDAQ
KR7134790005 134790 시디즈보통주 Sidiz,Inc KOSPI
Expand Down Expand Up @@ -2772,6 +2776,7 @@ KR7217910009 217910 에스제이켐 SJ-CHEM KONEX
KR7352770002 352770 클리노믹스 Clinomics Inc. KOSDAQ
KR7006380000 006380 카프로보통주 CAPRO KOSPI
KR7251370003 251370 와이엠티 YMT CO., LTD. KOSDAQ
KR7468760004 468760 유진기업인수목적10호 EUGENE SPECIAL PURPOSE ACQUISITION 10 COMPANY KOSDAQ
KR7200470003 200470 에이팩트 APACT Co., Ltd. KOSDAQ
KR7203450002 203450 유니온커뮤니티 Union community Co., Ltd. KOSDAQ
KR7190510008 190510 나무가 Namuga Co.,Ltd KOSDAQ
Expand Down
Loading