Skip to content

Commit

Permalink
merge: member Api 추가
Browse files Browse the repository at this point in the history
Feature/#125 member api 추가
  • Loading branch information
hong-sile authored Aug 28, 2024
2 parents 2e1de22 + ea5e7c5 commit 417fc02
Show file tree
Hide file tree
Showing 15 changed files with 188 additions and 4 deletions.
9 changes: 9 additions & 0 deletions src/main/java/play/pluv/login/application/LoginService.java
Original file line number Diff line number Diff line change
@@ -1,8 +1,10 @@
package play.pluv.login.application;

import java.util.List;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import play.pluv.login.domain.SocialLoginId;
import play.pluv.member.domain.Member;
import play.pluv.oauth.application.SocialLoginClientComposite;
import play.pluv.oauth.domain.OAuthMemberInfo;
Expand Down Expand Up @@ -36,4 +38,11 @@ public void addOtherLoginWay(

registerUpdater.addOtherLoginSource(memberId, memberInfo);
}

@Transactional(readOnly = true)
public List<MusicStreaming> getLoginTypes(final Long memberId) {
return registerReader.findMemberSocialLoginIds(memberId).stream()
.map(SocialLoginId::getSource)
.toList();
}
}
8 changes: 8 additions & 0 deletions src/main/java/play/pluv/login/application/RegisterReader.java
Original file line number Diff line number Diff line change
@@ -1,11 +1,13 @@
package play.pluv.login.application;

import java.util.List;
import java.util.Optional;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Component;
import org.springframework.transaction.annotation.Transactional;
import play.pluv.login.domain.SocialLoginId;
import play.pluv.login.domain.SocialLoginIdRepository;
import play.pluv.member.application.MemberReader;
import play.pluv.member.domain.Member;
import play.pluv.oauth.domain.OAuthMemberInfo;

Expand All @@ -15,9 +17,15 @@
public class RegisterReader {

private final SocialLoginIdRepository socialLoginIdRepository;
private final MemberReader memberReader;

public Optional<Member> findByOAuthMemberInfo(final OAuthMemberInfo memberInfo) {
return socialLoginIdRepository.findByOAuthMemberInfo(memberInfo)
.map(SocialLoginId::getMember);
}

public List<SocialLoginId> findMemberSocialLoginIds(final Long memberId) {
final Member member = memberReader.readById(memberId);
return socialLoginIdRepository.findAllByMember(member);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -22,15 +22,15 @@ public class RegisterUpdater {

public Member registerNewMember(final OAuthMemberInfo memberInfo) {
final NickName nickName = nickNameGenerator.generateNickName();
final Member member = new Member(nickName);
final Member member = memberRepository.save(new Member(nickName));

final SocialLoginId loginId = SocialLoginId.builder()
.oauthMemberInfo(memberInfo)
.member(member)
.build();
socialLoginIdRepository.save(loginId);

return memberRepository.save(member);
return member;
}

public void addOtherLoginSource(final Long memberId, final OAuthMemberInfo memberInfo) {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
package play.pluv.login.application.dto;

import static play.pluv.playlist.domain.MusicStreaming.YOUTUBE;

import java.util.List;
import play.pluv.playlist.domain.MusicStreaming;

public record LoginTypeResponse(
String type
) {

public static LoginTypeResponse from(final MusicStreaming type) {
if (type == YOUTUBE) {
return new LoginTypeResponse("google");
}
return new LoginTypeResponse(type.getName());
}

public static List<LoginTypeResponse> createList(final List<MusicStreaming> types) {
return types.stream()
.map(LoginTypeResponse::from)
.toList();
}
}
10 changes: 10 additions & 0 deletions src/main/java/play/pluv/login/controller/LoginController.java
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,9 @@
import static play.pluv.playlist.domain.MusicStreaming.YOUTUBE;

import jakarta.validation.Valid;
import java.util.List;
import lombok.RequiredArgsConstructor;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RestController;
Expand All @@ -14,7 +16,9 @@
import play.pluv.login.application.dto.AppleLoginRequest;
import play.pluv.login.application.dto.GoogleLoginRequest;
import play.pluv.login.application.dto.LoginResponse;
import play.pluv.login.application.dto.LoginTypeResponse;
import play.pluv.login.application.dto.SpotifyLoginRequest;
import play.pluv.playlist.domain.MusicStreaming;
import play.pluv.security.JwtMemberId;
import play.pluv.security.JwtProvider;

Expand Down Expand Up @@ -75,4 +79,10 @@ public BaseResponse<String> addAppleLoginWay(
loginService.addOtherLoginWay(APPLE, jwtMemberId.memberId(), loginRequest.idToken());
return BaseResponse.ok("");
}

@GetMapping("/login/type")
public BaseResponse<List<LoginTypeResponse>> getLoginType(final JwtMemberId jwtMemberId) {
final List<MusicStreaming> types = loginService.getLoginTypes(jwtMemberId.memberId());
return BaseResponse.ok(LoginTypeResponse.createList(types));
}
}
5 changes: 5 additions & 0 deletions src/main/java/play/pluv/login/domain/SocialLoginId.java
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
import lombok.NoArgsConstructor;
import play.pluv.member.domain.Member;
import play.pluv.oauth.domain.OAuthMemberInfo;
import play.pluv.playlist.domain.MusicStreaming;

@Entity
@NoArgsConstructor(access = PROTECTED)
Expand All @@ -36,4 +37,8 @@ public SocialLoginId(final Member member, final OAuthMemberInfo oauthMemberInfo)
this.member = member;
this.oauthMemberInfo = oauthMemberInfo;
}

public MusicStreaming getSource() {
return oauthMemberInfo.source();
}
}
Original file line number Diff line number Diff line change
@@ -1,8 +1,10 @@
package play.pluv.login.domain;

import java.util.List;
import java.util.Optional;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.Query;
import play.pluv.member.domain.Member;
import play.pluv.oauth.domain.OAuthMemberInfo;

public interface SocialLoginIdRepository extends JpaRepository<SocialLoginId, Long> {
Expand All @@ -16,4 +18,6 @@ public interface SocialLoginIdRepository extends JpaRepository<SocialLoginId, Lo
Optional<SocialLoginId> findByOAuthMemberInfo(final OAuthMemberInfo oauthMemberInfo);

Boolean existsByOauthMemberInfo(final OAuthMemberInfo oauthMemberInfo);

List<SocialLoginId> findAllByMember(final Member member);
}
5 changes: 5 additions & 0 deletions src/main/java/play/pluv/member/application/MemberReader.java
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
import org.springframework.stereotype.Component;
import org.springframework.transaction.annotation.Transactional;
import play.pluv.member.domain.Member;
import play.pluv.member.domain.NickName;
import play.pluv.member.domain.repository.MemberRepository;

@Component
Expand All @@ -16,4 +17,8 @@ public class MemberReader {
public Member readById(final Long memberId) {
return memberRepository.readById(memberId);
}

public NickName readNickName(final Long memberId) {
return readById(memberId).getNickName();
}
}
6 changes: 6 additions & 0 deletions src/main/java/play/pluv/member/application/MemberService.java
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
public class MemberService {

private final MemberUpdater memberUpdater;
private final MemberReader memberReader;

@Transactional
public void updateNickname(final Long memberId, final String nickName) {
Expand All @@ -20,4 +21,9 @@ public void updateNickname(final Long memberId, final String nickName) {
public void unregister(final Long memberId) {
memberUpdater.unregister(memberId);
}

@Transactional(readOnly = true)
public String getNickName(final Long memberId) {
return memberReader.readNickName(memberId).getNickName();
}
}
13 changes: 11 additions & 2 deletions src/main/java/play/pluv/member/controller/MemberController.java
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,10 @@
import jakarta.validation.Valid;
import lombok.RequiredArgsConstructor;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import play.pluv.base.BaseResponse;
import play.pluv.member.application.MemberService;
Expand All @@ -13,11 +15,12 @@

@RequiredArgsConstructor
@RestController
@RequestMapping("/member")
public class MemberController {

private final MemberService memberService;

@PostMapping("/member/nickname")
@PostMapping("/nickname")
public ResponseEntity<BaseResponse<String>> updateNickName(
@Valid @RequestBody final UpdateNickNameRequest updateNickNameRequest,
final JwtMemberId jwtMemberId
Expand All @@ -26,7 +29,13 @@ public ResponseEntity<BaseResponse<String>> updateNickName(
return ResponseEntity.ok(BaseResponse.ok(""));
}

@PostMapping("/member/unregister")
@GetMapping("/nickname")
public ResponseEntity<BaseResponse<String>> getNickName(final JwtMemberId jwtMemberId) {
final String nickName = memberService.getNickName(jwtMemberId.memberId());
return ResponseEntity.ok(BaseResponse.ok(nickName));
}

@PostMapping("/unregister")
public ResponseEntity<BaseResponse<String>> unregister(final JwtMemberId jwtMemberId) {
memberService.unregister(jwtMemberId.memberId());
return ResponseEntity.ok(BaseResponse.ok(""));
Expand Down
2 changes: 2 additions & 0 deletions src/main/java/play/pluv/member/domain/Member.java
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
import jakarta.persistence.Id;
import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.ToString;
import org.hibernate.annotations.SQLDelete;
import org.hibernate.annotations.Where;

Expand All @@ -18,6 +19,7 @@
@Getter
@SQLDelete(sql = "UPDATE member SET deleted = true WHERE id = ?")
@Where(clause = "deleted = false")
@ToString
public class Member {

@Id
Expand Down
30 changes: 30 additions & 0 deletions src/test/java/play/pluv/api/LoginApiTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -6,10 +6,12 @@
import static org.springframework.http.MediaType.APPLICATION_JSON_VALUE;
import static org.springframework.restdocs.headers.HeaderDocumentation.headerWithName;
import static org.springframework.restdocs.headers.HeaderDocumentation.requestHeaders;
import static org.springframework.restdocs.mockmvc.RestDocumentationRequestBuilders.get;
import static org.springframework.restdocs.mockmvc.RestDocumentationRequestBuilders.post;
import static org.springframework.restdocs.operation.preprocess.Preprocessors.preprocessRequest;
import static org.springframework.restdocs.operation.preprocess.Preprocessors.preprocessResponse;
import static org.springframework.restdocs.operation.preprocess.Preprocessors.prettyPrint;
import static org.springframework.restdocs.payload.JsonFieldType.ARRAY;
import static org.springframework.restdocs.payload.JsonFieldType.NUMBER;
import static org.springframework.restdocs.payload.JsonFieldType.STRING;
import static org.springframework.restdocs.payload.PayloadDocumentation.fieldWithPath;
Expand All @@ -20,6 +22,8 @@
import static play.pluv.playlist.domain.MusicStreaming.SPOTIFY;
import static play.pluv.playlist.domain.MusicStreaming.YOUTUBE;

import java.util.ArrayList;
import java.util.List;
import org.junit.jupiter.api.Test;
import play.pluv.login.application.dto.AppleLoginRequest;
import play.pluv.login.application.dto.GoogleLoginRequest;
Expand Down Expand Up @@ -197,4 +201,30 @@ public class LoginApiTest extends ApiTest {
)
));
}

@Test
void 연결한_소셜_계정확인하기() throws Exception {
final String token = "access Token";
final Long memberId = 10L;

setAccessToken(token, memberId);
when(loginService.getLoginTypes(memberId)).thenReturn(List.of(APPLE, YOUTUBE));

mockMvc.perform(get("/login/type")
.header(AUTHORIZATION, "Bearer " + token))
.andExpect(status().isOk())
.andDo(document("login-type",
preprocessRequest(prettyPrint()),
preprocessResponse(prettyPrint()),
requestHeaders(
headerWithName(AUTHORIZATION).description("Bearer Token")
),
responseFields(
fieldWithPath("code").type(NUMBER).description("상태 코드"),
fieldWithPath("msg").type(STRING).description("상태 코드에 해당하는 메시지"),
fieldWithPath("data[]").type(ARRAY).description("로그인 방법 목록"),
fieldWithPath("data[].type").type(STRING).description("유저가 등록한 로그인 방법")
)
));
}
}
25 changes: 25 additions & 0 deletions src/test/java/play/pluv/api/MemberApiTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,12 @@

import static com.epages.restdocs.apispec.MockMvcRestDocumentationWrapper.document;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
import static org.springframework.http.HttpHeaders.AUTHORIZATION;
import static org.springframework.http.MediaType.APPLICATION_JSON_VALUE;
import static org.springframework.restdocs.headers.HeaderDocumentation.headerWithName;
import static org.springframework.restdocs.headers.HeaderDocumentation.requestHeaders;
import static org.springframework.restdocs.mockmvc.RestDocumentationRequestBuilders.get;
import static org.springframework.restdocs.mockmvc.RestDocumentationRequestBuilders.post;
import static org.springframework.restdocs.payload.JsonFieldType.NUMBER;
import static org.springframework.restdocs.payload.JsonFieldType.STRING;
Expand Down Expand Up @@ -52,6 +54,29 @@ public class MemberApiTest extends ApiTest {
verify(memberService).updateNickname(memberId, nickName);
}

@Test
void 멤버_닉네임_조회() throws Exception {
final String token = "access Token";
final Long memberId = 10L;

setAccessToken(token, memberId);
when(memberService.getNickName(memberId)).thenReturn("nickName");

mockMvc.perform(get("/member/nickname")
.header(AUTHORIZATION, "Bearer " + token))
.andExpect(status().isOk())
.andDo(document("get-nickname",
requestHeaders(
headerWithName(AUTHORIZATION).description("Bearer Token")
),
responseFields(
fieldWithPath("code").type(NUMBER).description("상태 코드"),
fieldWithPath("msg").type(STRING).description("상태 코드에 해당하는 메시지"),
fieldWithPath("data").type(STRING).description("nickname")
)
));
}

@Test
void 멤버가_회원탈퇴한다() throws Exception {
final String token = "access Token";
Expand Down
Loading

0 comments on commit 417fc02

Please sign in to comment.