Skip to content

Commit

Permalink
✨ [STMT-258] 레거시 스터디 목록 조회 및 레거시 스터디 숨김 처리 API 구현 (#154)
Browse files Browse the repository at this point in the history
* 🗃️ [STMT-258] 스터디 멤버 테이블에 레거시 스터디 숨김 여부 컬럼 추가

* ✅ [STMT-258] 테스트 DB setup 데이터에 완료된 스터디 행 추가

* ✨ [STMT-258] 스터디 멤버 jpa entity에 레거시 스터디 숨김 여부 컬럼 추가

* ✨ [STMT-258] 멤버의 레거시 스터디 조회 쿼리 구현

* ✨ [STMT-258] 멤버의 레거시 스터디 조회 유스케이스 구현

* ✅ [STMT-258] 멤버의 레거시 스터디 조회 API 테스트 작성

* 📝 [STMT-258] 멤버의 레거시 스터디 조회 API 명세서 부가 설명 작성

* ✨ [STMT-258] 스터디 멤버 도메인에 레거시 숨김 플래그 속성 추가

* ✨ [STMT-258] 레거시 스터디인지 판별하는 검증 메서드 구현

* ✨ [STMT-258] 스터디 멤버 정보 업데이트 쿼리 메서드 구현

* ✨ [STMT-258] 레거시 스터디 숨김처리 유스케이스 구현

* ✨ [STMT-258] 레거시 스터디 숨김 API 구현

* 🩹 [STMT-258] 스터디 멤버 검증 메서드로 대체

* ✅ [STMT-258] 레거시 스터디 숨김 API 테스트 작성

* 📝 [STMT-258] 레거시 스터디 숨김 API 명세서 작성

* 🩹 [STMT-258] 레거시 스터디 숨김 스터디 존재 검증 로직 순서 변경
  • Loading branch information
05AM authored Oct 7, 2024
1 parent f4dd99b commit a923a59
Show file tree
Hide file tree
Showing 22 changed files with 372 additions and 17 deletions.
43 changes: 41 additions & 2 deletions src/docs/asciidoc/index.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -222,9 +222,13 @@ include::{snippets}/get-study-detail/fail/not-found/response-body.adoc[]
include::{snippets}/get-study-detail/fail/not-found/response-fields.adoc[]


=== 가입 스터디 리스트 조회
=== 스터디 리스트 조회

사용자가 가입된 스터디 리스트를 조회하는 API입니다.
사용자의 스터디 리스트를 조회하는 API입니다.

* 스터디 상태 정의
- `ACTIVE`: 사용자가 참여중인 스터디 중 미완료 목록 조회
- `FINSHED`: 사용자가 참여했던 완료 스터디 중 숨김처리 되지 않은 목록 조회

==== GET /api/v1/studies

Expand Down Expand Up @@ -553,6 +557,41 @@ include::{snippets}/get-study-member-can-send-grape/fail/study-not-found/respons
include::{snippets}/get-study-member-can-send-grape/fail/study-not-found/response-fields.adoc[]


=== 레거시 스터디 숨김 처리

멤버의 레거시 스터디를 숨김 처리하는 API입니다.

==== GET /v1/api/studies/{studyId}/legacy/hide

===== 요청
include::{snippets}/hide-legacy-study/success/http-request.adoc[]

====== 헤더
include::{snippets}/hide-legacy-study/success/request-headers.adoc[]

====== 경로 변수
include::{snippets}/hide-legacy-study/success/path-parameters.adoc[]

===== 응답 성공 (200)
include::{snippets}/hide-legacy-study/success/response-body.adoc[]
include::{snippets}/hide-legacy-study/success/response-fields.adoc[]

===== 응답 실패 (403)
.요청자가 스터디 멤버가 아닌 경우 경우
include::{snippets}/hide-legacy-study/fail/not-joined-study-member/response-body.adoc[]
include::{snippets}/hide-legacy-study/fail/not-joined-study-member/response-fields.adoc[]

===== 응답 실패 (404)
.존재하지 않는 스터디의 경우
include::{snippets}/hide-legacy-study/fail/study-not-exist/response-body.adoc[]
include::{snippets}/hide-legacy-study/fail/study-not-exist/response-fields.adoc[]

===== 응답 실패 (409)
.레거시 스터디가 아닌 경우
include::{snippets}/hide-legacy-study/fail/study-not-finished/response-body.adoc[]
include::{snippets}/hide-legacy-study/fail/study-not-finished/response-fields.adoc[]


== 파일 관리

=== Presigned URL 발급
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,11 @@ public enum ErrorCode {
ACTIVITY_STATUS_NOT_FOUND(HttpStatus.NOT_FOUND, "존재하지 않는 활동 상태 입니다."),
ACTIVITY_PARTICIPANT_NOT_FOUND(HttpStatus.NOT_FOUND, "존재하지 않는 활동 참가자입니다."),

/*
409 - CONFLICT
*/
ALREADY_DELETED_STUDY(HttpStatus.CONFLICT, "이미 삭제된 스터디 입니다."),
NOT_YET_FINISHED_STUDY(HttpStatus.CONFLICT, "완료되지 않은 스터디 입니다."),

/*
500 - INTERNAL SERVER ERROR
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,4 +17,15 @@ public interface JpaStudyRepository extends JpaRepository<StudyJpaEntity, Long>
+ "AND s.isFinished = false "
+ "AND s.isDeleted = false")
List<StudyJpaEntity> findActivesByMemberIdOrderByJoinedDate(@Param("memberId") Long memberId);


@Query("SELECT s "
+ "FROM StudyJpaEntity s "
+ "JOIN StudyMemberJpaEntity sm ON s.id = sm.study.id "
+ "WHERE sm.member.id = :memberId "
+ "AND sm.isLegacyHidden = false "
+ "AND s.isFinished = true "
+ "AND s.isDeleted = false "
+ "ORDER BY s.startDate ASC")
List<StudyJpaEntity> findLegacyStudiesNotHidden(@Param("memberId") Long memberId);
}
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,13 @@ public List<Study> getMemberRecentActiveStudies(Long memberId) {
return studyPersistenceMapper.toDomains(involvedStudies);
}

@Override
public List<Study> getMemberLegacyStudies(Long memberId) {
List<StudyJpaEntity> legacyStudies = studyRepository.findLegacyStudiesNotHidden(memberId);

return studyPersistenceMapper.toDomains(legacyStudies);
}

@Override
public boolean existsById(Long id) {
return studyRepository.existsById(id);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,4 +3,6 @@
public interface StudyValidationUseCase {

void checkById(Long id);

void checkLegacyStudy(Long id);
}
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,7 @@ public StudySimpleResponse toStudySimpleResponse(Study study) {
.build();
}

public JoinedStudiesResponse toMyStudiesResponse(List<Study> studies) {
public JoinedStudiesResponse toJoinedStudiesResponse(List<Study> studies) {
return studies.stream()
.map(this::toStudySimpleResponse)
.collect(collectingAndThen(toList(), JoinedStudiesResponse::new));
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,6 @@
public interface StudyQueryPort {

Study getById(Long id);

List<Study> getMemberRecentActiveStudies(Long memberId);
List<Study> getMemberLegacyStudies(Long memberId);
}
Original file line number Diff line number Diff line change
Expand Up @@ -38,13 +38,13 @@ public JoinedStudiesResponse getJoinedStudiesByStatus(GetJoinedStudyCommand comm
switch (status) {
case ACTIVE -> {
List<Study> activeJoinedStudies = studyQueryPort.getMemberRecentActiveStudies(command.memberId());
return studyUseCaseMapper.toMyStudiesResponse(activeJoinedStudies);
return studyUseCaseMapper.toJoinedStudiesResponse(activeJoinedStudies);
}

// TODO: 완료된 스터디 조회의 경우
// case FINISHED -> {
//
// }
case FINISHED -> {
List<Study> legacyStudies = studyQueryPort.getMemberLegacyStudies(command.memberId());
return studyUseCaseMapper.toJoinedStudiesResponse(legacyStudies);
}

default -> throw new StudyStatusNotExistsException(status.name());
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,8 +1,12 @@
package com.stumeet.server.study.application.service;

import com.stumeet.server.common.annotation.UseCase;
import com.stumeet.server.common.exception.model.InvalidStateException;
import com.stumeet.server.common.response.ErrorCode;
import com.stumeet.server.study.application.port.in.StudyValidationUseCase;
import com.stumeet.server.study.application.port.out.StudyQueryPort;
import com.stumeet.server.study.application.port.out.StudyValidationPort;
import com.stumeet.server.study.domain.Study;
import com.stumeet.server.study.domain.exception.StudyNotExistsException;
import lombok.RequiredArgsConstructor;
import org.springframework.transaction.annotation.Transactional;
Expand All @@ -13,11 +17,25 @@
public class StudyValidationService implements StudyValidationUseCase {

private final StudyValidationPort studyValidationPort;
private final StudyQueryPort studyQueryPort;

@Override
public void checkById(Long id) {
if (!studyValidationPort.existsById(id)) {
throw new StudyNotExistsException(id);
}
}

@Override
public void checkLegacyStudy(Long id) {
Study study = studyQueryPort.getById(id);

if (study.isDeleted()) {
throw new InvalidStateException(ErrorCode.ALREADY_DELETED_STUDY);
}

if (!study.isFinished()) {
throw new InvalidStateException(ErrorCode.NOT_YET_FINISHED_STUDY);
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
package com.stumeet.server.studymember.adapter.in.web;

import org.springframework.http.ResponseEntity;
import org.springframework.security.core.annotation.AuthenticationPrincipal;
import org.springframework.web.bind.annotation.PatchMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;

import com.stumeet.server.common.annotation.WebAdapter;
import com.stumeet.server.common.auth.model.LoginMember;
import com.stumeet.server.common.model.ApiResponse;
import com.stumeet.server.common.response.SuccessCode;
import com.stumeet.server.studymember.application.port.in.LegacyStudyHideUseCase;

import lombok.RequiredArgsConstructor;

@WebAdapter
@RequestMapping("/api/v1/studies/{studyId}")
@RequiredArgsConstructor
public class LegacyStudyHideApi {

private final LegacyStudyHideUseCase legacyStudyHideUseCase;

@PatchMapping("/legacy/hide")
public ResponseEntity<ApiResponse<Void>> hideLegacyStudy(
@AuthenticationPrincipal LoginMember member,
@PathVariable(name = "studyId") Long studyId
) {
legacyStudyHideUseCase.hideLegacyStudyForMember(studyId, member.getId());

return ResponseEntity.ok(ApiResponse.success(SuccessCode.UPDATE_SUCCESS));
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -35,4 +35,8 @@ public class StudyMemberJpaEntity extends BaseTimeEntity {
@Column(name = "is_sent_grape")
@Comment("포도알 전송 여부")
private boolean isSentGrape;

@Column(name = "is_legacy_hidden")
@Comment("레거시 스터디 숨김 처리 여부")
private boolean isLegacyHidden;
}
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
import com.stumeet.server.studymember.application.port.in.response.SimpleStudyMemberResponse;
import com.stumeet.server.studymember.application.port.out.StudyMemberJoinPort;
import com.stumeet.server.studymember.application.port.out.StudyMemberQueryPort;
import com.stumeet.server.studymember.application.port.out.StudyMemberUpdatePort;
import com.stumeet.server.studymember.application.port.out.StudyMemberValidationPort;
import com.stumeet.server.studymember.domain.StudyMember;
import lombok.RequiredArgsConstructor;
Expand All @@ -13,16 +14,12 @@

@PersistenceAdapter
@RequiredArgsConstructor
public class StudyMemberPersistenceAdapter implements StudyMemberJoinPort, StudyMemberQueryPort, StudyMemberValidationPort {
public class StudyMemberPersistenceAdapter implements StudyMemberJoinPort, StudyMemberQueryPort, StudyMemberValidationPort,
StudyMemberUpdatePort {

private final JpaStudyMemberRepository jpaStudyMemberRepository;
private final StudyMemberPersistenceMapper studyMemberPersistenceMapper;

@Override
public void join(StudyMember studyMember) {
jpaStudyMemberRepository.save(studyMemberPersistenceMapper.toEntity(studyMember));
}

@Override
public List<SimpleStudyMemberResponse> findStudyMembers(Long studyId) {
return jpaStudyMemberRepository.findStudyMembersByStudyId(studyId);
Expand All @@ -35,6 +32,17 @@ public StudyMember findStudyMember(Long studyId, Long memberId) {
return studyMemberPersistenceMapper.toDomain(entity);
}

@Override
public void join(StudyMember studyMember) {
jpaStudyMemberRepository.save(studyMemberPersistenceMapper.toEntity(studyMember));
}

@Override
public void update(StudyMember studyMember) {
StudyMemberJpaEntity entity = studyMemberPersistenceMapper.toEntity(studyMember);
jpaStudyMemberRepository.save(entity);
}

@Override
public boolean isSentGrape(Long studyId, Long memberId) {
return jpaStudyMemberRepository.isSentGrape(studyId, memberId);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ public StudyMemberJpaEntity toEntity(StudyMember domain) {
.study(studyPersistenceMapper.toEntity(domain.getStudy()))
.isAdmin(domain.isAdmin())
.isSentGrape(domain.isSentGrape())
.isLegacyHidden(domain.isLegacyHidden())
.build();
}

Expand All @@ -29,6 +30,7 @@ public StudyMember toDomain(StudyMemberJpaEntity entity) {
.study(studyPersistenceMapper.toDomain(entity.getStudy()))
.isAdmin(entity.isAdmin())
.isSentGrape(entity.isSentGrape())
.isLegacyHidden(entity.isLegacyHidden())
.build();
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
package com.stumeet.server.studymember.application.port.in;

public interface LegacyStudyHideUseCase {

void hideLegacyStudyForMember(Long studyId, Long member);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
package com.stumeet.server.studymember.application.port.out;

import com.stumeet.server.studymember.domain.StudyMember;

public interface StudyMemberUpdatePort {

void update(StudyMember studyMember);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
package com.stumeet.server.studymember.application.service;

import org.springframework.transaction.annotation.Transactional;

import com.stumeet.server.common.annotation.UseCase;
import com.stumeet.server.study.application.port.in.StudyValidationUseCase;
import com.stumeet.server.studymember.application.port.in.LegacyStudyHideUseCase;
import com.stumeet.server.studymember.application.port.in.StudyMemberValidationUseCase;
import com.stumeet.server.studymember.application.port.out.StudyMemberQueryPort;
import com.stumeet.server.studymember.application.port.out.StudyMemberUpdatePort;
import com.stumeet.server.studymember.application.port.out.StudyMemberValidationPort;
import com.stumeet.server.studymember.domain.StudyMember;

import lombok.RequiredArgsConstructor;

@UseCase
@RequiredArgsConstructor
@Transactional
public class LegacyStudyHideService implements LegacyStudyHideUseCase {

private final StudyValidationUseCase studyValidationUseCase;
private final StudyMemberValidationUseCase studyMemberValidationUseCase;

private final StudyMemberQueryPort studyMemberQueryPort;
private final StudyMemberUpdatePort studyMemberUpdatePort;

@Override
public void hideLegacyStudyForMember(Long studyId, Long memberId) {
studyValidationUseCase.checkLegacyStudy(studyId);
studyMemberValidationUseCase.checkStudyJoinMember(studyId, memberId);

StudyMember studyMember = studyMemberQueryPort.findStudyMember(studyId, memberId);
studyMember.hideLegacyStudy();

studyMemberUpdatePort.update(studyMember);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -18,4 +18,10 @@ public class StudyMember {
private boolean isAdmin;

private boolean isSentGrape;

private boolean isLegacyHidden;

public void hideLegacyStudy() {
this.isLegacyHidden = true;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
ALTER TABLE study_member
ADD COLUMN is_legacy_hidden TINYINT(1) NOT NULL DEFAULT false;
4 changes: 4 additions & 0 deletions src/test/java/com/stumeet/server/stub/StudyStub.java
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,10 @@ public static Long getFutureStudyId() {
return 2L;
}

public static Long getFinishedStudyId() {
return 3L;
}

public static StudyCreateCommand getStudyCreateCommand() {
return new StudyCreateCommand(
"어학",
Expand Down
Loading

0 comments on commit a923a59

Please sign in to comment.