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

[BE] issue187: 특정 스터디에서 나의 role을 확인하는 API 생성 #193

Merged
merged 19 commits into from
Aug 4, 2022
Merged
Show file tree
Hide file tree
Changes from 6 commits
Commits
Show all changes
19 commits
Select commit Hold shift + click to select a range
43b3b40
test: 특정 스터디에서 나의 role을 확인하는 API 인수 테스트 작성
jaejae-yoo Aug 3, 2022
3c41971
refactor: api 명세 변경
jaejae-yoo Aug 3, 2022
ed84cd4
feat: 스터디에서 사용자의 role을 확인하는 기능
jaejae-yoo Aug 3, 2022
588edcf
fix: 충돌 해결
jaejae-yoo Aug 3, 2022
184bd65
feat: 스터디에서 사용자의 역할을 조회하는 rest docs API 생성
jaejae-yoo Aug 4, 2022
d5fed86
refactor: 스터디에서 나의 역할을 조회하는 서비스 로직 메서드 분리
jaejae-yoo Aug 4, 2022
2bef2b1
fix: 충돌 해결
jaejae-yoo Aug 4, 2022
220a59c
fix: rest docs 문제 해결
jaejae-yoo Aug 4, 2022
4fd28f8
fix: 충돌 해결
jaejae-yoo Aug 4, 2022
dbcc5ad
refactor: MyRole -> MemberRole 클래스명 변경
jaejae-yoo Aug 4, 2022
8a26d57
refactor: 스터디 사용자 역할을 판별하는 로직 스터디 객체로 이동
jaejae-yoo Aug 4, 2022
785d1d7
test: 사용자 역할 조회 사용자 인증 테스트 추가
jaejae-yoo Aug 4, 2022
7b678f4
Merge branch 'develop' into feat/187-check-is-my-study
jaejae-yoo Aug 4, 2022
f9e5a04
refactor: rest docs 변경
jaejae-yoo Aug 4, 2022
12bfe15
refactor: rest docs Mock Mvc -> RestAssuerd로 변경
jaejae-yoo Aug 4, 2022
7102615
test: 사용자가 존재하지 않을 때, 스터디가 존재하지 않을 때 예외 추가
jaejae-yoo Aug 4, 2022
2237674
test: study Id가 string일 경우 400 에러 테스트 추가
jaejae-yoo Aug 4, 2022
99b3c86
fix: 충돌 해결
jaejae-yoo Aug 4, 2022
19ed32e
fix: 충돌 해결
jaejae-yoo Aug 4, 2022
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
5 changes: 5 additions & 0 deletions backend/src/docs/asciidoc/index.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -33,3 +33,8 @@ operation::reviews/list[snippets='http-request,http-response']

=== 리뷰 특정 개수 조회
operation::reviews/list-certain-number[snippets='http-request,http-response']

[[My-Role]]

=== 스터디에서 사용자 역할 조회
operation::members/me/role[snippets='http-request,request-headers,request-parameters,http-response,response-fields']
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ public class AuthRequestMatchConfig {
public AuthenticationRequestMatcher authenticationRequestMatcher() {
return new AuthenticationRequestMatcherBuilder()
.addUpAuthenticationPath(HttpMethod.POST, "/api/studies", "/api/studies/\\d+/reviews")
.addUpAuthenticationPath(HttpMethod.GET, "/api/my/studies")
.addUpAuthenticationPath(HttpMethod.GET, "/api/my/studies", "/api/members/me/role")
.build();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,12 @@

import com.woowacourse.moamoa.auth.config.AuthenticationPrincipal;
import com.woowacourse.moamoa.study.service.MyStudyService;
import com.woowacourse.moamoa.study.service.response.MyRoleResponse;
import com.woowacourse.moamoa.study.service.response.MyStudiesResponse;

import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;

import lombok.RequiredArgsConstructor;
Expand All @@ -21,4 +23,11 @@ public ResponseEntity<MyStudiesResponse> getMyStudies(@AuthenticationPrincipal L
final MyStudiesResponse myStudiesResponse = myStudyService.getStudies(githubId);
return ResponseEntity.ok().body(myStudiesResponse);
}

@GetMapping("/api/members/me/role")
public ResponseEntity<MyRoleResponse> getMyRoleInStudy(
@AuthenticationPrincipal Long githubId, @RequestParam(name = "study-id") Long studyId
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

final이 빠졌어요..!

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

추가했습니다! 👍

) {
return ResponseEntity.ok().body(myStudyService.findMyRoleInStudy(githubId, studyId));
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

깰끔

}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
package com.woowacourse.moamoa.study.domain;

public enum MyRole {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

MemberRole 가 더 명시적일 것 같습니다!

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

좋아요👍 클래스명 수정했습니다.


MEMBER, NON_MEMBER, OWNER
}
Original file line number Diff line number Diff line change
Expand Up @@ -12,12 +12,14 @@
import javax.persistence.ElementCollection;
import javax.persistence.Embeddable;
import javax.persistence.JoinColumn;
import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.ToString;

@Embeddable
@ToString
@NoArgsConstructor(access = PROTECTED)
@Getter
@ToString
public class Participants {

@Column(name = "current_member_count")
Expand Down Expand Up @@ -51,6 +53,10 @@ boolean isAlreadyParticipated(Long memberId) {
return participants.contains(new Participant(memberId)) || ownerId.equals(memberId);
}

public boolean isParticipate(Long memberId) {
return participants.contains(new Participant(memberId));
}
Comment on lines +56 to +58
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

기존에 존재하는 isAlreadyParticipated 메소드를 활용해도 Service 로직에 이상이 없을 것 같아요!
(owner 를 먼저 검사하고 있어서)

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

물론 로직 자체로는 문제가 없지만, 해당 사용자가 참여자인지 확인하는 메서드로 분리하는 게 더 명확하다고 생각해서 나누는 게 좋을 것 같아요! 기존의 isAlreadyParticipated의 메서드명 때문에 헷갈릴 것 같아서요!


int getSize() {
return size;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,15 +2,22 @@

import com.woowacourse.moamoa.member.domain.Member;
import com.woowacourse.moamoa.member.domain.repository.MemberRepository;
import com.woowacourse.moamoa.member.service.exception.MemberNotFoundException;
import com.woowacourse.moamoa.study.domain.MyRole;
import com.woowacourse.moamoa.study.domain.Participants;
import com.woowacourse.moamoa.study.domain.Study;
import com.woowacourse.moamoa.study.domain.repository.StudyRepository;
import com.woowacourse.moamoa.study.query.MyStudyDao;
import com.woowacourse.moamoa.study.service.exception.StudyNotFoundException;
import com.woowacourse.moamoa.study.service.response.MyRoleResponse;
import com.woowacourse.moamoa.member.service.exception.MemberNotFoundException;
import com.woowacourse.moamoa.study.query.data.StudyOwnerAndTagsData;
import com.woowacourse.moamoa.study.service.response.MyStudyResponse;
import com.woowacourse.moamoa.study.query.data.MyStudySummaryData;
import com.woowacourse.moamoa.study.service.response.MyStudiesResponse;

import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.stream.Collectors;

import org.springframework.stereotype.Service;
Expand All @@ -27,6 +34,8 @@ public class MyStudyService {

private final MemberRepository memberRepository;

private final StudyRepository studyRepository;

public MyStudiesResponse getStudies(final Long githubId) {
final Member member = memberRepository.findByGithubId(githubId)
.orElseThrow(MemberNotFoundException::new);
Expand All @@ -51,4 +60,24 @@ private List<MyStudyResponse> mapToResponse(final List<MyStudySummaryData> myStu
))
.collect(Collectors.toList());
}

public MyRoleResponse findMyRoleInStudy(final Long githubId, final Long studyId) {
final Member member = memberRepository.findByGithubId(githubId)
.orElseThrow(MemberNotFoundException::new);
final Study study = studyRepository.findById(studyId)
.orElseThrow(StudyNotFoundException::new);

final Participants participants = study.getParticipants();
return getMyRoleResponse(member, participants);
}

private MyRoleResponse getMyRoleResponse(final Member member, final Participants participants) {
if (Objects.equals(participants.getOwnerId(), member.getId())) {
return new MyRoleResponse(MyRole.OWNER);
}
if (participants.isParticipate(member.getId())) {
return new MyRoleResponse(MyRole.MEMBER);
}
return new MyRoleResponse(MyRole.NON_MEMBER);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
package com.woowacourse.moamoa.study.service.response;

import com.woowacourse.moamoa.study.domain.MyRole;
import lombok.AllArgsConstructor;
import lombok.Getter;
import lombok.NoArgsConstructor;

@AllArgsConstructor
@NoArgsConstructor
@Getter
public class MyRoleResponse {

private MyRole role;
}
45 changes: 36 additions & 9 deletions backend/src/main/resources/static/docs/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -461,6 +461,7 @@ <h1>MOAMOA</h1>
<li><a href="#_리뷰_작성">리뷰 작성</a></li>
<li><a href="#_리뷰_전체_조회">리뷰 전체 조회</a></li>
<li><a href="#_리뷰_특정_개수_조회">리뷰 특정 개수 조회</a></li>
<li><a href="#My-Role">스터디에서 사용자 역할 조회</a></li>
</ul>
</li>
</ul>
Expand Down Expand Up @@ -492,7 +493,7 @@ <h4 id="_github_로그인_http_response"><a class="link" href="#_github_로그
Vary: Access-Control-Request-Method
Vary: Access-Control-Request-Headers
Content-Type: application/json
Content-Length: 30
Content-Length: 28

{
"token" : "JWT 토큰"
Expand All @@ -514,9 +515,9 @@ <h4 id="_스터디_생성_http_request"><a class="link" href="#_스터디_생성
<div class="content">
<pre class="highlightjs highlight nowrap"><code data-lang="http" class="language-http hljs">POST /api/studies HTTP/1.1
Content-Type: application/json
Authorization: Bearer aaaaa.bbbbb.ccccc
Authorization: Bearer header.payload.signature
Accept: application/json
Content-Length: 348
Content-Length: 338
Host: localhost:8080

{
Expand Down Expand Up @@ -568,7 +569,7 @@ <h4 id="_스터디_목록_조회_http_response"><a class="link" href="#_스터
Vary: Access-Control-Request-Method
Vary: Access-Control-Request-Headers
Content-Type: application/json
Content-Length: 808
Content-Length: 773

{
"studies" : [ {
Expand Down Expand Up @@ -623,9 +624,9 @@ <h4 id="_리뷰_작성_http_request"><a class="link" href="#_리뷰_작성_http_
<div class="content">
<pre class="highlightjs highlight nowrap"><code data-lang="http" class="language-http hljs">POST /api/studies/1/reviews HTTP/1.1
Content-Type: application/json
Authorization: Bearer aaaaa.bbbbb.ccccc
Authorization: Bearer header.payload.signature
Accept: application/json
Content-Length: 55
Content-Length: 53
Host: localhost:8080

{
Expand Down Expand Up @@ -669,7 +670,7 @@ <h4 id="_리뷰_전체_조회_http_response"><a class="link" href="#_리뷰_전
Vary: Access-Control-Request-Method
Vary: Access-Control-Request-Headers
Content-Type: application/json
Content-Length: 1326
Content-Length: 1279

{
"reviews" : [ {
Expand Down Expand Up @@ -745,7 +746,7 @@ <h4 id="_리뷰_특정_개수_조회_http_response"><a class="link" href="#_리
Vary: Access-Control-Request-Method
Vary: Access-Control-Request-Headers
Content-Type: application/json
Content-Length: 683
Content-Length: 658

{
"reviews" : [ {
Expand Down Expand Up @@ -777,13 +778,39 @@ <h4 id="_리뷰_특정_개수_조회_http_response"><a class="link" href="#_리
</div>
</div>
</div>
<div class="sect2">
<h3 id="My-Role"><a class="link" href="#My-Role">스터디에서 사용자 역할 조회</a></h3>
<div class="sect3">
<h4 id="My-Role_http_request"><a class="link" href="#My-Role_http_request">HTTP request</a></h4>
<div class="listingblock">
<div class="content">
<pre class="highlightjs highlight nowrap"><code data-lang="http" class="language-http hljs">GET /api/members/me/role?study-id=3 HTTP/1.1
Content-Type: application/json
Authorization: Bearer header.payload.signature
Accept: application/json
Host: localhost:8080</code></pre>
</div>
</div>
</div>
<div class="sect3">
<h4 id="My-Role_http_response"><a class="link" href="#My-Role_http_response">HTTP response</a></h4>
<div class="listingblock">
<div class="content">
<pre class="highlightjs highlight nowrap"><code data-lang="http" class="language-http hljs">HTTP/1.1 200 OK
Vary: Origin
Vary: Access-Control-Request-Method
Vary: Access-Control-Request-Headers</code></pre>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
<div id="footer">
<div id="footer-text">
Version 0.0.1-SNAPSHOT<br>
Last updated 2022-08-03 14:36:51 +0900
Last updated 2022-08-03 21:57:59 +0900
</div>
</div>
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/9.15.6/styles/github.min.css">
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,6 @@
import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Test;
import org.springframework.http.HttpStatus;
import org.springframework.test.context.jdbc.Sql;

public class AuthAcceptanceTest extends AcceptanceTest {

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,9 @@

import static org.hamcrest.Matchers.contains;
import static org.hamcrest.Matchers.is;
import static org.springframework.http.HttpHeaders.AUTHORIZATION;
import static org.springframework.http.HttpHeaders.CONTENT_TYPE;
import static org.springframework.http.MediaType.APPLICATION_JSON_VALUE;

import com.woowacourse.acceptance.AcceptanceTest;
import com.woowacourse.moamoa.auth.service.oauthclient.response.GithubProfileResponse;
Expand Down Expand Up @@ -103,4 +106,20 @@ void getMyStudies() {
.body("studies[0].tags.id", contains(2, 4, 5))
.body("studies[0].tags.name", contains("4기", "FE", "React"));
}

@Test
@DisplayName("특정 스터디에서 나의 Role을 확인한다.")
void isMyStudy() {
final String token = getBearerTokenBySignInOrUp(new GithubProfileResponse(4L, "verus", "https://image", "github.com"));

RestAssured.given().log().all()
.header(CONTENT_TYPE, APPLICATION_JSON_VALUE)
.header(AUTHORIZATION, token)
.queryParam("study-id", 7)
.when()
.get("/api/members/me/role")
.then().log().all()
.statusCode(HttpStatus.OK.value())
.body("role", is("OWNER"));
}
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

OWNER 이외에 NON_MEMBER 나 MEMBER 등의 테스트 케이스도 추가해주면 좋을 것 같아요!! (꼭 인수테스트에서 할 필요는 없을 것 같구...)

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

service에서 테스트하고 있습니다!

}
Original file line number Diff line number Diff line change
Expand Up @@ -15,8 +15,10 @@
import com.woowacourse.moamoa.review.controller.SearchingReviewController;
import com.woowacourse.moamoa.review.service.ReviewService;
import com.woowacourse.moamoa.review.service.SearchingReviewService;
import com.woowacourse.moamoa.study.controller.MyStudyController;
import com.woowacourse.moamoa.study.controller.SearchingStudyController;
import com.woowacourse.moamoa.study.controller.StudyController;
import com.woowacourse.moamoa.study.service.MyStudyService;
import com.woowacourse.moamoa.study.service.SearchingStudyService;
import com.woowacourse.moamoa.study.service.StudyService;
import org.junit.jupiter.api.BeforeEach;
Expand All @@ -36,7 +38,8 @@
StudyController.class,
SearchingStudyController.class,
ReviewController.class,
SearchingReviewController.class
SearchingReviewController.class,
MyStudyController.class
})
@ExtendWith(RestDocumentationExtension.class)
@Import(JwtTokenProvider.class)
Expand Down Expand Up @@ -75,6 +78,9 @@ public class DocumentationTest {
@MockBean
protected SearchingReviewService searchingReviewService;

@MockBean
protected MyStudyService myStudyService;

@BeforeEach
void setUp(WebApplicationContext webApplicationContext, RestDocumentationContextProvider restDocumentation) {
mockMvc = MockMvcBuilders.webAppContextSetup(webApplicationContext)
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
package com.woowacourse.moamoa.docs;

import static com.woowacourse.fixtures.AuthFixtures.JWT_토큰;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyLong;
import static org.mockito.BDDMockito.given;
import static org.springframework.restdocs.headers.HeaderDocumentation.headerWithName;
import static org.springframework.restdocs.headers.HeaderDocumentation.requestHeaders;
import static org.springframework.restdocs.mockmvc.MockMvcRestDocumentation.document;
import static org.springframework.restdocs.payload.PayloadDocumentation.fieldWithPath;
import static org.springframework.restdocs.payload.PayloadDocumentation.requestFields;
import static org.springframework.restdocs.payload.PayloadDocumentation.responseFields;
import static org.springframework.restdocs.request.RequestDocumentation.parameterWithName;
import static org.springframework.restdocs.request.RequestDocumentation.requestParameters;
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get;
import static org.springframework.test.web.servlet.result.MockMvcResultHandlers.print;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;

import com.woowacourse.moamoa.auth.service.response.TokenResponse;
import com.woowacourse.moamoa.study.domain.MyRole;
import com.woowacourse.moamoa.study.service.response.MyRoleResponse;
import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Test;
import org.springframework.http.HttpHeaders;
import org.springframework.http.MediaType;
import org.springframework.restdocs.payload.JsonFieldType;

public class MyStudyDocumentationTest extends DocumentationTest {

@DisplayName("스터디에서 사용자의 역할을 조회한다.")
@Test
void getMyRoleInStudy() throws Exception {
given(myStudyService.findMyRoleInStudy(any(), any())).willReturn(new MyRoleResponse(MyRole.MEMBER));

mockMvc.perform(get("/api/members/me/role")
.header(HttpHeaders.AUTHORIZATION, "Bearer " + JWT_토큰)
.queryParam("study-id", "3")
.contentType(MediaType.APPLICATION_JSON_VALUE)
.accept(MediaType.APPLICATION_JSON))
.andDo(document("members/me/role",
requestHeaders(
headerWithName("Authorization").description(
"Bearer Token")),
requestParameters(parameterWithName("study-id").description("스터디 ID")),
responseFields(fieldWithPath("role").type(JsonFieldType.STRING).description("해당 스터디에서 사용자의 역할"))))
.andDo(print())
.andExpect(status().isOk());
}
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

인수테스트로 문서화하기로 해서 이 테스트는 삭제해도 될 것 같습니다!

}
Loading