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 @@ -5,6 +5,7 @@
import com.ject.studytrip.auth.presentation.dto.request.KakaoLoginRequest;
import com.ject.studytrip.auth.presentation.dto.request.KakaoSignupRequest;
import com.ject.studytrip.auth.presentation.dto.response.TokenResponse;
import com.ject.studytrip.member.application.dto.CreateMemberCommand;
import com.ject.studytrip.member.application.service.MemberService;
import com.ject.studytrip.member.domain.model.Member;
import com.ject.studytrip.member.domain.model.SocialProvider;
Expand All @@ -19,21 +20,26 @@ public class AuthFacade {

public TokenResponse kakaoLogin(KakaoLoginRequest request) {
KakaoUserInfoResponse response = kakaoLoginService.getKakaoUserInfo(request.code());

Member member =
memberService.getMemberBySocialProviderAndSocialId(
SocialProvider.KAKAO, response.kakaoId());

return kakaoLoginService.getTokens(member.getId().toString(), member.getRole().name());
}

public TokenResponse kakaoSignup(KakaoSignupRequest request) {
KakaoUserInfoResponse response = kakaoLoginService.getKakaoUserInfo(request.code());
Member member =
memberService.createMemberFromKakao(
CreateMemberCommand command =
CreateMemberCommand.of(
response.kakaoId(),
response.getEmail(),
response.getProfileImage(),
request.category(),
request.nickname());
request.nickname(),
request.category());

Member member = memberService.createMemberFromKakao(command);

return kakaoLoginService.getTokens(member.getId().toString(), member.getRole().name());
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
import io.swagger.v3.oas.annotations.tags.Tag;
import jakarta.validation.Valid;
import lombok.RequiredArgsConstructor;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
Expand All @@ -27,7 +28,7 @@ public class AuthController {
public ResponseEntity<StandardResponse> kakaoLogin(
@Valid @RequestBody KakaoLoginRequest request) {
TokenResponse response = authFacade.kakaoLogin(request);
return ResponseEntity.ok(StandardResponse.success(200, response));
return ResponseEntity.ok(StandardResponse.success(HttpStatus.OK.value(), response));
}

@Operation(
Expand All @@ -37,6 +38,6 @@ public ResponseEntity<StandardResponse> kakaoLogin(
public ResponseEntity<StandardResponse> kakaoSignup(
@Valid @RequestBody KakaoSignupRequest request) {
TokenResponse response = authFacade.kakaoSignup(request);
return ResponseEntity.ok(StandardResponse.success(200, response));
return ResponseEntity.ok(StandardResponse.success(HttpStatus.OK.value(), response));
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,8 @@ public enum UrlConstants {
LOCAL_API_SERVER_URL("http://localhost:8080"),

// TODO: 개발, 운영 도메인 URL 추가 작업
LOCAL_DOMAIN_URL("http://localhost:3000"),
LOCAL_SECURE_DOMAIN_URL("https://localhost:3000"),
LOCAL_DOMAIN_URL("http://localhost:5173"),
LOCAL_SECURE_DOMAIN_URL("https://localhost:5173"),
;

private final String value;
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
package com.ject.studytrip.member.application.dto;

public record CreateMemberCommand(
String socialId, String email, String profileImage, String nickname, String category) {
public static CreateMemberCommand of(
String socialId, String email, String profileImage, String nickname, String category) {
return new CreateMemberCommand(socialId, email, profileImage, nickname, category);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
package com.ject.studytrip.member.application.dto;

import com.ject.studytrip.trip.application.dto.TripCount;

public record MemberDetail(MemberInfo memberInfo, TripCount tripCount, long studyLogCount) {
public static MemberDetail from(
MemberInfo memberInfo, TripCount tripCount, long studyLogCount) {
return new MemberDetail(memberInfo, tripCount, studyLogCount);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
package com.ject.studytrip.member.application.dto;

import com.ject.studytrip.global.util.DateUtil;
import com.ject.studytrip.member.domain.model.Member;
import com.ject.studytrip.member.domain.model.MemberCategory;
import com.ject.studytrip.member.domain.model.MemberRole;
import com.ject.studytrip.member.domain.model.SocialProvider;

public record MemberInfo(
Long memberId,
SocialProvider socialProvider,
String socialId,
String email,
String nickname,
String profileImage,
MemberCategory category,
MemberRole role,
String createdAt,
String updatedAt,
String deletedAt) {
public static MemberInfo from(Member member) {
return new MemberInfo(
member.getId(),
member.getSocialProvider(),
member.getSocialId(),
member.getEmail(),
member.getNickname(),
member.getProfileImage(),
member.getCategory(),
member.getRole(),
DateUtil.formatDateTime(member.getCreatedAt()),
DateUtil.formatDateTime(member.getUpdatedAt()),
DateUtil.formatDateTime(member.getDeletedAt()));
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
package com.ject.studytrip.member.application.facade;

import com.ject.studytrip.member.application.dto.MemberDetail;
import com.ject.studytrip.member.application.dto.MemberInfo;
import com.ject.studytrip.member.application.service.MemberService;
import com.ject.studytrip.member.domain.model.Member;
import com.ject.studytrip.member.presentation.dto.request.UpdateMemberRequest;
import com.ject.studytrip.studylog.application.service.StudyLogService;
import com.ject.studytrip.trip.application.dto.TripCount;
import com.ject.studytrip.trip.application.service.TripService;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Component;

@Component
@RequiredArgsConstructor
public class MemberFacade {
private final MemberService memberService;
private final TripService tripService;
private final StudyLogService studyLogService;

public void updateNicknameAndCategoryIfPresent(Long memberId, UpdateMemberRequest request) {
Member member = memberService.getActiveMemberById(memberId);

memberService.updateNicknameAndCategoryIfPresent(member, request);
}

public void deleteMember(Long memberId) {
Member member = memberService.getActiveMemberById(memberId);

memberService.deleteMember(member);
}

public MemberDetail getMemberDetail(Long memberId) {
Member member = memberService.getActiveMemberById(memberId);
TripCount tripCount = tripService.getActiveTripCountsByMemberId(memberId);
long studyLogCount = studyLogService.getActiveStudyLogCountByMemberId(memberId);

MemberInfo memberInfo = MemberInfo.from(member);

return MemberDetail.from(memberInfo, tripCount, studyLogCount);
}
}
Original file line number Diff line number Diff line change
@@ -1,13 +1,17 @@
package com.ject.studytrip.member.application.service;

import static org.springframework.util.StringUtils.hasText;

import com.ject.studytrip.global.exception.CustomException;
import com.ject.studytrip.member.application.dto.CreateMemberCommand;
import com.ject.studytrip.member.domain.error.MemberErrorCode;
import com.ject.studytrip.member.domain.model.Member;
import com.ject.studytrip.member.domain.model.MemberCategory;
import com.ject.studytrip.member.domain.model.SocialProvider;
import com.ject.studytrip.member.domain.policy.MemberPolicy;
import com.ject.studytrip.member.domain.repository.MemberRepository;
import com.ject.studytrip.member.factory.MemberFactory;
import com.ject.studytrip.member.presentation.dto.request.UpdateMemberRequest;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
Expand All @@ -17,6 +21,34 @@
public class MemberService {
private final MemberRepository memberRepository;

@Transactional
public Member createMemberFromKakao(CreateMemberCommand command) {
validateMemberIsUnique(SocialProvider.KAKAO, command.socialId());

MemberCategory memberCategory = convertToMemberCategory(command.category());
Member member =
MemberFactory.createFromKakao(
command.socialId(),
command.email(),
command.profileImage(),
command.nickname(),
memberCategory);

return memberRepository.save(member);
}

@Transactional
public void updateNicknameAndCategoryIfPresent(Member member, UpdateMemberRequest request) {
MemberCategory memberCategory = convertToMemberCategory(request.category());

member.update(request.nickname(), memberCategory);
}

@Transactional
public void deleteMember(Member member) {
member.updateDeletedAt();
}

@Transactional(readOnly = true)
public Member getMember(Long memberId) {
return memberRepository
Expand All @@ -32,18 +64,20 @@ public Member getMemberBySocialProviderAndSocialId(
.orElseThrow(() -> new CustomException(MemberErrorCode.MEMBER_NEED_SIGNUP));
}

@Transactional
public Member createMemberFromKakao(
String kakaoId, String email, String profileImage, String category, String nickname) {
boolean exists =
memberRepository.existsBySocialProviderAndSocialId(SocialProvider.KAKAO, kakaoId);
MemberPolicy.validateNickname(nickname);
MemberPolicy.validateNewMember(exists);

MemberCategory memberCategory = MemberCategory.from(category);
Member member =
MemberFactory.fromKakao(kakaoId, email, profileImage, nickname, memberCategory);
@Transactional(readOnly = true)
public Member getActiveMemberById(Long memberId) {
return memberRepository
.findByIdAndDeletedAtIsNull(memberId)
.orElseThrow(() -> new CustomException(MemberErrorCode.MEMBER_NOT_FOUND));
}

return memberRepository.save(member);
private void validateMemberIsUnique(SocialProvider socialProvider, String socialId) {
boolean isMemberDuplicated =
memberRepository.existsBySocialProviderAndSocialId(socialProvider, socialId);
MemberPolicy.validateNotDuplicated(isMemberDuplicated);
}

private MemberCategory convertToMemberCategory(String categoryName) {
return hasText(categoryName) ? MemberCategory.from(categoryName) : null;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -6,12 +6,18 @@

@RequiredArgsConstructor
public enum MemberErrorCode implements ErrorCode {
MEMBER_CATEGORY_REQUIRED(HttpStatus.BAD_REQUEST, "멤버 카테고리는 필수입니다."),
MEMBER_NICKNAME_REQUIRED(HttpStatus.BAD_REQUEST, "멤버 닉네임은 필수입니다."),
// 400
INVALID_MEMBER_CATEGORY(HttpStatus.BAD_REQUEST, "유효하지 않은 멤버 카테고리입니다."),
MEMBER_NICKNAME_DUPLICATED(HttpStatus.BAD_REQUEST, "이미 사용 중인 닉네임입니다."),
MEMBER_ALREADY_DELETED(HttpStatus.BAD_REQUEST, "해당 멤버는 이미 삭제되었습니다."),

// 404
MEMBER_NOT_FOUND(HttpStatus.NOT_FOUND, "멤버를 찾을 수 없습니다."),

// 409
MEMBER_NEED_SIGNUP(HttpStatus.CONFLICT, "회원가입이 필요한 사용자입니다."),
MEMBER_ALREADY_EXISTS(HttpStatus.CONFLICT, "이미 가입된 사용자입니다."),
INVALID_MEMBER_CATEGORY(HttpStatus.BAD_REQUEST, "유효하지 않은 멤버 카테고리입니다.");
;

private final HttpStatus status;
private final String message;
Expand Down
19 changes: 18 additions & 1 deletion src/main/java/com/ject/studytrip/member/domain/model/Member.java
Original file line number Diff line number Diff line change
@@ -1,7 +1,10 @@
package com.ject.studytrip.member.domain.model;

import static org.springframework.util.StringUtils.hasText;

import com.ject.studytrip.global.common.entity.BaseTimeEntity;
import jakarta.persistence.*;
import java.time.LocalDateTime;
import lombok.*;

@Entity
Expand All @@ -25,7 +28,7 @@ public class Member extends BaseTimeEntity {
@Column(nullable = false, unique = true)
private String email;

@Column(nullable = false, unique = true)
@Column(nullable = false)
private String nickname;

private String profileImage;
Expand Down Expand Up @@ -54,4 +57,18 @@ public static Member of(
.role(role)
.build();
}

// 프로필 이미지 수정 로직 추가 예정
public void update(String nickname, MemberCategory category) {
if (hasText(nickname) && !nickname.equals(this.nickname)) { // 다른 경우에만 닉네임 수정
this.nickname = nickname;
}
if (category != null && category != this.category) { // 다른 경우에만 카테고리 수정
this.category = category;
}
}

public void updateDeletedAt() {
this.deletedAt = LocalDateTime.now();
}
}
Original file line number Diff line number Diff line change
@@ -1,7 +1,5 @@
package com.ject.studytrip.member.domain.model;

import static org.springframework.util.StringUtils.hasText;

import com.ject.studytrip.global.exception.CustomException;
import com.ject.studytrip.member.domain.error.MemberErrorCode;

Expand All @@ -13,10 +11,6 @@ public enum MemberCategory {
;

public static MemberCategory from(String category) {
if (!hasText(category)) {
throw new CustomException(MemberErrorCode.MEMBER_CATEGORY_REQUIRED);
}

try {
return MemberCategory.valueOf(category);
} catch (IllegalArgumentException e) {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,24 +1,22 @@
package com.ject.studytrip.member.domain.policy;

import static io.jsonwebtoken.lang.Strings.hasText;

import com.ject.studytrip.global.exception.CustomException;
import com.ject.studytrip.member.domain.error.MemberErrorCode;
import com.ject.studytrip.member.domain.model.Member;
import lombok.AccessLevel;
import lombok.NoArgsConstructor;

@NoArgsConstructor(access = AccessLevel.PRIVATE)
public class MemberPolicy {

public static void validateNickname(String nickname) {
if (!hasText(nickname)) {
throw new CustomException(MemberErrorCode.MEMBER_NICKNAME_REQUIRED);
public static void validateNotDuplicated(boolean exists) {
if (exists) {
throw new CustomException(MemberErrorCode.MEMBER_ALREADY_EXISTS);
}
}

public static void validateNewMember(boolean exists) {
if (exists) {
throw new CustomException(MemberErrorCode.MEMBER_ALREADY_EXISTS);
public static void validateNotDeleted(Member member) {
if (member.getDeletedAt() != null) {
throw new CustomException(MemberErrorCode.MEMBER_ALREADY_DELETED);
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -13,4 +13,6 @@ Optional<Member> findBySocialProviderAndSocialId(
Optional<Member> findById(Long id);

Member save(Member member);

Optional<Member> findByIdAndDeletedAtIsNull(Long id);
}
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@

@NoArgsConstructor(access = AccessLevel.PRIVATE)
public class MemberFactory {
public static Member fromKakao(
public static Member createFromKakao(
String kakaoId,
String email,
String profileImage,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,4 +10,6 @@ Optional<Member> findBySocialProviderAndSocialId(
SocialProvider socialProvider, String socialId);

boolean existsBySocialProviderAndSocialId(SocialProvider socialProvider, String socialId);

Optional<Member> findByIdAndDeletedAtIsNull(Long id);
}
Loading