-
Notifications
You must be signed in to change notification settings - Fork 4
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] 기존 api 중 폴링으로 인한 변경 반영, studyId로 참여코드 조회 api 구현 #569
Changes from all commits
120c2a1
0400fe0
96115eb
10f6215
d48d4db
06fd494
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,32 @@ | ||
package harustudy.backend.participantcode.controller; | ||
|
||
import harustudy.backend.auth.Authenticated; | ||
import harustudy.backend.auth.dto.AuthMember; | ||
import harustudy.backend.participantcode.dto.ParticipantCodeResponse; | ||
import harustudy.backend.participantcode.service.ParticipantCodeService; | ||
import io.swagger.v3.oas.annotations.Operation; | ||
import io.swagger.v3.oas.annotations.tags.Tag; | ||
import lombok.RequiredArgsConstructor; | ||
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; | ||
|
||
@Tag(name = "참여 코드 관련 기능") | ||
@RequiredArgsConstructor | ||
@RestController | ||
public class ParticipantCodeController { | ||
|
||
private final ParticipantCodeService participantCodeService; | ||
|
||
@Operation(summary = "스터디 아이디로 참여 코드 조회") | ||
@GetMapping("/api/participant-codes") | ||
public ResponseEntity<ParticipantCodeResponse> findParticipantCodeByStudyId( | ||
@Authenticated AuthMember authMember, | ||
@RequestParam Long studyId | ||
) { | ||
ParticipantCodeResponse response = participantCodeService.findParticipantCodeByStudyId( | ||
studyId); | ||
return ResponseEntity.ok(response); | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,10 @@ | ||
package harustudy.backend.participantcode.dto; | ||
|
||
import harustudy.backend.participantcode.domain.ParticipantCode; | ||
|
||
public record ParticipantCodeResponse(String participantCode) { | ||
|
||
public static ParticipantCodeResponse from(ParticipantCode participantCode) { | ||
return new ParticipantCodeResponse(participantCode.getCode()); | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,10 +1,13 @@ | ||
package harustudy.backend.participantcode.repository; | ||
|
||
import harustudy.backend.participantcode.domain.ParticipantCode; | ||
import harustudy.backend.study.domain.Study; | ||
import java.util.Optional; | ||
import org.springframework.data.jpa.repository.JpaRepository; | ||
|
||
public interface ParticipantCodeRepository extends JpaRepository<ParticipantCode, Long> { | ||
|
||
Optional<ParticipantCode> findByCode(String code); | ||
|
||
Optional<ParticipantCode> findByStudy(Study study); | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,28 @@ | ||
package harustudy.backend.participantcode.service; | ||
|
||
import harustudy.backend.participantcode.domain.ParticipantCode; | ||
import harustudy.backend.participantcode.dto.ParticipantCodeResponse; | ||
import harustudy.backend.participantcode.repository.ParticipantCodeRepository; | ||
import harustudy.backend.study.domain.Study; | ||
import harustudy.backend.study.exception.ParticipantCodeNotFoundException; | ||
import harustudy.backend.study.repository.StudyRepository; | ||
import lombok.RequiredArgsConstructor; | ||
import org.springframework.stereotype.Service; | ||
import org.springframework.transaction.annotation.Transactional; | ||
|
||
@RequiredArgsConstructor | ||
@Transactional | ||
@Service | ||
public class ParticipantCodeService { | ||
|
||
private final StudyRepository studyRepository; | ||
private final ParticipantCodeRepository participantCodeRepository; | ||
|
||
@Transactional(readOnly = true) | ||
public ParticipantCodeResponse findParticipantCodeByStudyId(Long studyId) { | ||
Study study = studyRepository.findByIdIfExists(studyId); | ||
ParticipantCode participantCode = participantCodeRepository.findByStudy(study) | ||
.orElseThrow(ParticipantCodeNotFoundException::new); | ||
return ParticipantCodeResponse.from(participantCode); | ||
} | ||
} |
This file was deleted.
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -4,16 +4,15 @@ | |
import harustudy.backend.member.domain.Member; | ||
import harustudy.backend.member.exception.MemberNotFoundException; | ||
import harustudy.backend.member.repository.MemberRepository; | ||
import harustudy.backend.participantcode.domain.GenerationStrategy; | ||
import harustudy.backend.participantcode.domain.ParticipantCode; | ||
import harustudy.backend.participant.domain.Participant; | ||
import harustudy.backend.participant.repository.ParticipantRepository; | ||
import harustudy.backend.participantcode.domain.GenerationStrategy; | ||
import harustudy.backend.participantcode.domain.ParticipantCode; | ||
import harustudy.backend.participantcode.repository.ParticipantCodeRepository; | ||
import harustudy.backend.study.domain.Study; | ||
import harustudy.backend.study.dto.CreateStudyRequest; | ||
import harustudy.backend.study.dto.CreateStudyResponse; | ||
import harustudy.backend.study.dto.StudyResponse; | ||
import harustudy.backend.study.dto.StudiesResponse; | ||
import harustudy.backend.study.dto.StudyResponse; | ||
import harustudy.backend.study.exception.ParticipantCodeNotFoundException; | ||
import harustudy.backend.study.exception.StudyNotFoundException; | ||
import harustudy.backend.study.repository.StudyRepository; | ||
|
@@ -65,21 +64,20 @@ private StudiesResponse findStudyByMemberId(Long memberId) { | |
return StudiesResponse.from(studies); | ||
} | ||
|
||
// TODO: N+1 | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 꼼꼼함... 좋네요 👍 |
||
private List<Study> mapToStudies(List<Participant> participants) { | ||
return participants.stream() | ||
.map(Participant::getStudy) | ||
.toList(); | ||
} | ||
|
||
public CreateStudyResponse createStudy(CreateStudyRequest request) { | ||
public Long createStudy(CreateStudyRequest request) { | ||
Study study = new Study(request.name(), request.totalCycle(), | ||
request.timePerCycle()); | ||
Study savedStudy = studyRepository.save(study); | ||
participantCodeRepository.save(generateUniqueCode(savedStudy)); | ||
|
||
ParticipantCode participantCode = generateUniqueCode(study); | ||
participantCodeRepository.save(participantCode); | ||
|
||
return CreateStudyResponse.from(savedStudy, participantCode); | ||
return savedStudy.getId(); | ||
} | ||
|
||
private ParticipantCode generateUniqueCode(Study study) { | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -18,16 +18,17 @@ | |
import harustudy.backend.content.dto.WritePlanRequest; | ||
import harustudy.backend.content.dto.WriteRetrospectRequest; | ||
import harustudy.backend.integration.LoginResponse; | ||
import harustudy.backend.participant.dto.ParticipateStudyRequest; | ||
import harustudy.backend.participant.dto.ParticipantsResponse; | ||
import harustudy.backend.participant.dto.ParticipateStudyRequest; | ||
import harustudy.backend.participantcode.dto.ParticipantCodeResponse; | ||
import harustudy.backend.study.dto.CreateStudyRequest; | ||
import harustudy.backend.study.dto.CreateStudyResponse; | ||
import harustudy.backend.study.dto.StudyResponse; | ||
import harustudy.backend.study.dto.StudiesResponse; | ||
import harustudy.backend.study.dto.StudyResponse; | ||
import jakarta.servlet.http.Cookie; | ||
import java.nio.charset.StandardCharsets; | ||
import java.util.List; | ||
import java.util.Map; | ||
import org.junit.jupiter.api.Assertions; | ||
import org.junit.jupiter.api.BeforeEach; | ||
import org.junit.jupiter.api.DisplayNameGeneration; | ||
import org.junit.jupiter.api.DisplayNameGenerator.ReplaceUnderscores; | ||
|
@@ -80,8 +81,7 @@ void setUp() { | |
@Test | ||
void 회원으로_스터디를_진행한다() throws Exception { | ||
LoginResponse 로그인_정보 = 구글_로그인을_진행한다(); | ||
String 참여_코드 = 스터디를_개설한다(로그인_정보); | ||
Long 스터디_아이디 = 스터디를_조회한다(로그인_정보, 참여_코드); | ||
Long 스터디_아이디 = 스터디를_개설한다(로그인_정보); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 스터디를 개설하는 사람은 플로우에서 참여 코드가 필요 없어졌군요. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 이거 까먹을 것 같은데 이슈로 만들어둘게용 There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 만들까 했는데 남의 참여코드로 참여까지만 하면 되서 전체 플로우 만들기보다 그냥 서비스 테스트정도만 만들었어요! |
||
Long 참여자_아이디 = 스터디에_참여한다(로그인_정보, 스터디_아이디); | ||
스터디_상태를_다음_단계로_넘긴다(로그인_정보, 스터디_아이디); | ||
스터디_계획을_작성한다(로그인_정보, 스터디_아이디, 참여자_아이디); | ||
|
@@ -106,8 +106,7 @@ void setUp() { | |
@Test | ||
void 비회원으로_스터디를_진행한다() throws Exception { | ||
LoginResponse 로그인_정보 = 비회원_로그인을_진행한다(); | ||
String 참여_코드 = 스터디를_개설한다(로그인_정보); | ||
Long 스터디_아이디 = 스터디를_조회한다(로그인_정보, 참여_코드); | ||
Long 스터디_아이디 = 스터디를_개설한다(로그인_정보); | ||
Long 진행도_아이디 = 스터디에_참여한다(로그인_정보, 스터디_아이디); | ||
스터디_상태를_다음_단계로_넘긴다(로그인_정보, 스터디_아이디); | ||
스터디_계획을_작성한다(로그인_정보, 스터디_아이디, 진행도_아이디); | ||
|
@@ -118,6 +117,13 @@ void setUp() { | |
스터디_종료_후_결과_조회(로그인_정보, 스터디_아이디); | ||
} | ||
|
||
@Test | ||
void 비회원으로_타인의_스터디에_참여한다() throws Exception { | ||
String 참여_코드 = 타인의_스터디_참여_코드를_얻는다(); | ||
LoginResponse 로그인_정보 = 비회원_로그인을_진행한다(); | ||
참여_코드로_스터디_아이디를_얻는다(로그인_정보, 참여_코드); | ||
} | ||
|
||
private List<StudyResponse> 회원으로_진행했던_모든_스터디_목록을_조회한다(LoginResponse 로그인_정보) | ||
throws Exception { | ||
long memberId = Long.parseLong(jwtTokenProvider | ||
|
@@ -170,7 +176,7 @@ void setUp() { | |
return new LoginResponse(tokenResponse, refreshToken); | ||
} | ||
|
||
private String 스터디를_개설한다(LoginResponse 로그인_정보) throws Exception { | ||
private Long 스터디를_개설한다(LoginResponse 로그인_정보) throws Exception { | ||
CreateStudyRequest request = new CreateStudyRequest("studyName", 1, 20); | ||
String jsonRequest = objectMapper.writeValueAsString(request); | ||
MvcResult result = mockMvc.perform( | ||
|
@@ -180,24 +186,11 @@ void setUp() { | |
.header(HttpHeaders.AUTHORIZATION, 로그인_정보.createAuthorizationHeader())) | ||
.andExpect(status().isCreated()) | ||
.andReturn(); | ||
String jsonResponse = result.getResponse().getContentAsString(StandardCharsets.UTF_8); | ||
CreateStudyResponse response = objectMapper.readValue(jsonResponse, | ||
CreateStudyResponse.class); | ||
return response.participantCode(); | ||
} | ||
String locationHeader = result.getResponse().getHeader(HttpHeaders.LOCATION); | ||
|
||
private Long 스터디를_조회한다(LoginResponse 로그인_정보, String 참여_코드) throws Exception { | ||
MvcResult result = mockMvc.perform( | ||
get("/api/studies") | ||
.param("participantCode", 참여_코드) | ||
.header(HttpHeaders.AUTHORIZATION, 로그인_정보.createAuthorizationHeader())) | ||
.andExpect(status().isOk()) | ||
.andReturn(); | ||
String jsonResponse = result.getResponse().getContentAsString(StandardCharsets.UTF_8); | ||
StudiesResponse responses = objectMapper.readValue(jsonResponse, | ||
StudiesResponse.class); | ||
StudyResponse response = responses.studies().get(0); | ||
return response.studyId(); | ||
String[] parsed = locationHeader.split("/"); | ||
System.out.println(locationHeader); | ||
return Long.parseLong(parsed[3]); | ||
} | ||
|
||
private Long 스터디에_참여한다(LoginResponse 로그인_정보, Long 스터디_아이디) throws Exception { | ||
|
@@ -265,4 +258,38 @@ void setUp() { | |
|
||
assertThat(jsonResponse.participants()).hasSize(1); | ||
} | ||
|
||
private String 타인의_스터디_참여_코드를_얻는다() throws Exception { | ||
LoginResponse 로그인_정보 = 비회원_로그인을_진행한다(); | ||
Long 스터디_아이디 = 스터디를_개설한다(로그인_정보); | ||
return 스터디_아이디로_참여_코드를_얻는다(로그인_정보, 스터디_아이디); | ||
} | ||
|
||
private String 스터디_아이디로_참여_코드를_얻는다(LoginResponse 로그인_정보, Long 스터디_아이디) throws Exception { | ||
MvcResult result = mockMvc.perform(get("/api/participant-codes") | ||
.param("studyId", 스터디_아이디.toString()) | ||
.accept(MediaType.APPLICATION_JSON) | ||
.header(HttpHeaders.AUTHORIZATION, 로그인_정보.createAuthorizationHeader())) | ||
.andExpect(status().isOk()) | ||
.andReturn(); | ||
|
||
String response = result.getResponse().getContentAsString(StandardCharsets.UTF_8); | ||
ParticipantCodeResponse jsonResponse = objectMapper.readValue(response, | ||
ParticipantCodeResponse.class); | ||
|
||
assertThat(jsonResponse.participantCode()).hasSize(6); | ||
return jsonResponse.participantCode(); | ||
} | ||
|
||
private void 참여_코드로_스터디_아이디를_얻는다(LoginResponse 로그인_정보, String 참여_코드) throws Exception { | ||
MvcResult result = mockMvc.perform(get("/api/studies") | ||
.param("participantCode", 참여_코드) | ||
.accept(MediaType.APPLICATION_JSON) | ||
.header(HttpHeaders.AUTHORIZATION, 로그인_정보.createAuthorizationHeader())) | ||
.andExpect(status().isOk()) | ||
.andReturn(); | ||
String response = result.getResponse().getContentAsString(StandardCharsets.UTF_8); | ||
Assertions.assertDoesNotThrow(() -> objectMapper.readValue(response, | ||
StudyResponse.class)); | ||
} | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
progressStep를 쓸지 progress를 쓸지 저희끼리 결정하고 가면 좋을 듯 하네여!(나중에 컨벤션 통일시키려면)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
이거 progress로 사용하기로 해서 마코가 merge 하기 전에 수정했던 것 같은데 표현이 혼재되어 있었네용... 저는 개인적으로 step 붙여주는게 통일감 있어서 좋기는 합니다! 그리고 In-Progress 상태에서 단계를 나타낸다는 의미로 progressStep 네이밍도 좋은 것 같아욤