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

✨ [STMT-200] 스터디 수정 api 구현 #116

Merged
merged 17 commits into from
Apr 19, 2024
Merged
Show file tree
Hide file tree
Changes from 9 commits
Commits
Show all changes
17 commits
Select commit Hold shift + click to select a range
bfb8dc4
:recycle: [STMT-166] 스터디 생성 리팩토링
05AM Apr 13, 2024
f598605
:recycle: [STMT-200] 스터디 정기 모임 일정에서 반복을 독립적인 클래스로 분리
05AM Apr 13, 2024
f744bb4
:recycle: [STMT-200] 스터디 도메인 리팩터링에 따른 응용계층, 인프라계층 mapper 수정
05AM Apr 13, 2024
c56e4dc
:recycle: [STMT-200] 스터디 태그 엔티티와 스터디 엔티티의 연관관계 수정
05AM Apr 13, 2024
270333c
:sparkles: [STMT-200] 스터디 수정 api 구현
05AM Apr 13, 2024
4af473a
:white_check_mark: [STMT-167] display name 수정
05AM Apr 13, 2024
e9bc326
:adhesive_bandage: [STMT-167] 스터디 정보 수정 api return http code 수정 CREAT…
05AM Apr 13, 2024
cc8b7c3
:white_check_mark: [STMT-167] 스터디 수정 api 테스트 케이스 작성
05AM Apr 13, 2024
630afe3
:memo: [STMT-167] 스터디 생성, 수정 api 명세서 수정 및 작성
05AM Apr 12, 2024
fc46a1f
:construction: [STMT-167] null safe 체크 반영
05AM Apr 15, 2024
8fd1685
:construction: [STMT-167] null safe 체크 추가 반영
05AM Apr 15, 2024
7456a05
:recycle: [STMT-167] 값으로 빈 배열을 받기 위해 파일과 요청본문을 request part로 분리
05AM Apr 15, 2024
507256b
:white_check_mark: [STMT-167] 스터디 생성/수정 api null 없애기 리팩토링 이후 테스트 반영
05AM Apr 15, 2024
2f534ca
:lipstick: [STMT-167] test db 예시 row 값을 현실적인 값으로 변경
05AM Apr 15, 2024
6981f4d
:memo: [STMT-167] request part 분리에 따른 API 명세서 수정
05AM Apr 15, 2024
2389781
:white_check_mark: [STMT-167] MultiPartFile을 범용성있게 요청 파라미터 이름을 넣어 생성할…
05AM Apr 19, 2024
8c79e9a
:white_check_mark: [STMT-167] MultiPart 관련 인스턴스를 생성하는 factory 클래스로 구현
05AM Apr 19, 2024
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
44 changes: 44 additions & 0 deletions src/docs/asciidoc/index.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -233,8 +233,16 @@ include::{snippets}/get-study-detail/fail/not-found/response-fields.adoc[]

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

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

===== 파트
include::{snippets}/create-study/success/request-parts.adoc[]

===== 매개변수
include::{snippets}/create-study/success/query-parameters.adoc[]

===== 응답 성공 (200)

include::{snippets}/create-study/success/response-body.adoc[]
Expand All @@ -253,6 +261,42 @@ include::{snippets}/create-study/fail/invalid-study-meeting-schedule/response-bo
include::{snippets}/create-study/fail/invalid-study-meeting-schedule/response-fields.adoc[]


=== 스터디 수정

스터디 정보를 수정하는 API 입니다.

==== PATCH /api/v1/studies/{studyId}

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

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

===== 파트
include::{snippets}/update-study/success/request-parts.adoc[]

===== 매개변수
include::{snippets}/update-study/success/query-parameters.adoc[]

===== 응답 성공 (200)

include::{snippets}/update-study/success/response-body.adoc[]
include::{snippets}/update-study/success/response-fields.adoc[]

===== 응답 실패 (404)

.존재하지 않는 스터디 분야 ID를 요청한 경우

include::{snippets}/update-study/fail/study-field-not-found/response-body.adoc[]
include::{snippets}/update-study/fail/study-field-not-found/response-fields.adoc[]

.일정 반복 유형 DAILY일 때를 제외하고 반복일을 null 값으로 요청한 경우

include::{snippets}/update-study/fail/invalid-study-meeting-schedule/response-body.adoc[]
include::{snippets}/update-study/fail/invalid-study-meeting-schedule/response-fields.adoc[]


== 스터디 멤버 관리

=== 스터디 멤버 조회
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ public enum SuccessCode {
* 200 - OK
*/
GET_SUCCESS(HttpStatus.OK, "조회에 성공했습니다."),
UPDATE_SUCCESS(HttpStatus.OK, "수정에 성공했습니다."),
STUDY_LEAVE_SUCCESS(HttpStatus.OK, "스터디 탈퇴에 성공했습니다."),
STUDY_KICK_SUCCESS(HttpStatus.OK, "스터디원 강퇴에 성공했습니다."),

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ public ResponseEntity<ApiResponse<Void>> create(
@AuthenticationPrincipal LoginMember member,
@Valid StudyCreateCommand request
) {
studyCreateUseCase.create(request, member.getMember());
studyCreateUseCase.create(request, member.getMember().getId());

return new ResponseEntity<>(
ApiResponse.success(SuccessCode.STUDY_CREATE_SUCCESS),
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
package com.stumeet.server.study.adapter.in.web;

import org.springframework.http.HttpStatus;
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.study.application.port.in.StudyUpdateUseCase;
import com.stumeet.server.study.application.port.in.command.StudyUpdateCommand;

import jakarta.validation.Valid;
import lombok.RequiredArgsConstructor;

@WebAdapter
@RequiredArgsConstructor
@RequestMapping("/api/v1/studies")
public class StudyUpdateApi {

private final StudyUpdateUseCase studyUpdateUseCase;

@PatchMapping("/{studyId}")
public ResponseEntity<ApiResponse<Void>> update(
@AuthenticationPrincipal LoginMember member,
@PathVariable Long studyId,
@Valid StudyUpdateCommand request
) {
studyUpdateUseCase.update(studyId, member.getMember().getId(), request);

return new ResponseEntity<>(
ApiResponse.success(SuccessCode.UPDATE_SUCCESS),
HttpStatus.OK);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -5,4 +5,6 @@
import com.stumeet.server.study.adapter.out.persistance.entity.StudyTagJpaEntity;

public interface JpaStudyTagRepository extends JpaRepository<StudyTagJpaEntity, Long> {

void deleteAllByStudyId(Long studyId);
}
Original file line number Diff line number Diff line change
Expand Up @@ -17,10 +17,21 @@ public class StudyTagPersistenceAdapter implements StudyTagCommandPort {
private final StudyTagPersistenceMapper studyTagPersistenceMapper;

@Override
public List<String> saveAll(List<String> studyTags, Long studyId) {
public List<String> saveAllStudyTags(List<String> studyTags, Long studyId) {
List<StudyTagJpaEntity> entities =
studyTagRepository.saveAll(studyTagPersistenceMapper.toEntities(studyTags, studyId));

return studyTagPersistenceMapper.toDomains(entities);
}

@Override
public void clearStudyTags(Long studyId) {
studyTagRepository.deleteAllByStudyId(studyId);
}

@Override
public void replaceStudyTags(List<String> newStudyTags, Long studyId) {
clearStudyTags(studyId);
saveAllStudyTags(newStudyTags, studyId);
}
}
Original file line number Diff line number Diff line change
@@ -1,14 +1,18 @@
package com.stumeet.server.study.adapter.out.persistance.entity;

import com.stumeet.server.study.domain.StudyField;

import jakarta.persistence.EnumType;
import jakarta.persistence.Enumerated;
import jakarta.persistence.FetchType;
import jakarta.persistence.OneToMany;

import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.LocalTime;

import java.util.List;

import org.hibernate.annotations.ColumnDefault;
import org.hibernate.annotations.Comment;

Expand All @@ -19,7 +23,6 @@
import jakarta.persistence.GeneratedValue;
import jakarta.persistence.GenerationType;
import jakarta.persistence.Id;
import jakarta.persistence.JoinColumn;
import jakarta.persistence.Table;
import lombok.AccessLevel;
import lombok.AllArgsConstructor;
Expand All @@ -40,8 +43,7 @@ public class StudyJpaEntity extends BaseTimeEntity {
@Comment("스터디 그룹 아이디")
private Long id;

@OneToMany(orphanRemoval = true)
@JoinColumn(name = "study_id")
@OneToMany(mappedBy = "studyId", fetch = FetchType.EAGER)
private List<StudyTagJpaEntity> studyTags;

@Enumerated(EnumType.STRING)
Expand Down Expand Up @@ -111,4 +113,4 @@ public Boolean getIsFinished() {
public Boolean getIsDeleted() {
return this.isDeleted;
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
import jakarta.persistence.GeneratedValue;
import jakarta.persistence.GenerationType;
import jakarta.persistence.Id;
import jakarta.persistence.JoinColumn;
import jakarta.persistence.Table;
import lombok.AccessLevel;
import lombok.AllArgsConstructor;
Expand All @@ -27,7 +28,7 @@ public class StudyTagJpaEntity {
@Comment("스터디 태그 id")
private Long id;

@Column(name = "study_id", nullable = false)
@JoinColumn(name = "study_id", nullable = false)
@Comment("스터디 id")
private Long studyId;

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,24 +4,23 @@

import org.springframework.stereotype.Component;

import com.stumeet.server.study.domain.Repetition;
import com.stumeet.server.study.domain.RepetitionType;
import com.stumeet.server.study.domain.StudyMeetingSchedule;

@Component
public class MeetingRepetitionPersistenceMapper {

private static final String REPEAT_DELIMITER = ";";

public StudyMeetingSchedule.Repetition toDomain(String meetingRepetition) {
public Repetition toDomain(String meetingRepetition) {
List<String> repetitionElements = List.of(meetingRepetition.split(REPEAT_DELIMITER));

return StudyMeetingSchedule.Repetition.builder()
.type(RepetitionType.valueOf(repetitionElements.getFirst()))
.dates(repetitionElements.subList(1, repetitionElements.size()))
.build();
return Repetition.of(
RepetitionType.valueOf(repetitionElements.getFirst()),
repetitionElements.subList(1, repetitionElements.size()));
}

public String toColumn(StudyMeetingSchedule.Repetition repetition) {
public String toColumn(Repetition repetition) {
String dates = repetition.getDates() != null
? String.join(REPEAT_DELIMITER, repetition.getDates())
: null;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,20 +2,18 @@

import com.stumeet.server.study.adapter.out.persistance.entity.StudyJpaEntity;
import com.stumeet.server.study.domain.StudyDomain;

import lombok.RequiredArgsConstructor;

import org.springframework.stereotype.Component;

@Component
@RequiredArgsConstructor
public class StudyDomainPersistenceMapper {

private final StudyTagPersistenceMapper studyTagPersistenceMapper;

public StudyDomain toDomain(StudyJpaEntity entity) {
return StudyDomain.builder()
.studyField(entity.getStudyField())
.studyTags(studyTagPersistenceMapper.toDomains(entity.getStudyTags()))
.build();
private final StudyTagPersistenceMapper studyTagPersistenceMapper;

}
public StudyDomain toDomain(StudyJpaEntity entity) {
return StudyDomain.of(entity.getStudyField(), studyTagPersistenceMapper.toDomains(entity.getStudyTags()));
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
package com.stumeet.server.study.adapter.out.persistance.mapper;

import java.time.LocalTime;

import org.springframework.stereotype.Component;

import com.stumeet.server.study.domain.StudyMeetingSchedule;

import lombok.RequiredArgsConstructor;

@Component
@RequiredArgsConstructor
public class StudyMeetingSchedulePersistenceMapper {

private final MeetingRepetitionPersistenceMapper meetingRepetitionPersistenceMapper;

public StudyMeetingSchedule toDomain(LocalTime meetingTime, String meetingRepetition) {
return StudyMeetingSchedule.of(meetingTime, meetingRepetitionPersistenceMapper.toDomain(meetingRepetition));
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@

import com.stumeet.server.study.adapter.out.persistance.entity.StudyJpaEntity;
import com.stumeet.server.study.domain.Study;
import com.stumeet.server.study.domain.StudyMeetingSchedule;
import com.stumeet.server.study.domain.StudyPeriod;

import lombok.RequiredArgsConstructor;
Expand All @@ -14,8 +13,9 @@
public class StudyPersistenceMapper {

private final StudyDomainPersistenceMapper studyDomainPersistenceMapper;
private final MeetingRepetitionPersistenceMapper meetingRepetitionPersistenceMapper;
private final StudyTagPersistenceMapper studyTagPersistenceMapper;
private final StudyMeetingSchedulePersistenceMapper studyMeetingSchedulePersistenceMapper;
private final MeetingRepetitionPersistenceMapper meetingRepetitionPersistenceMapper;

public Study toDomain(StudyJpaEntity entity) {
return Study.builder()
Expand All @@ -25,15 +25,9 @@ public Study toDomain(StudyJpaEntity entity) {
.region(entity.getRegion())
.intro(entity.getIntro())
.rule(entity.getRule())
.period(StudyPeriod.builder()
.startDate(entity.getStartDate())
.endDate(entity.getEndDate())
.build())
.period(StudyPeriod.of(entity.getStartDate(), entity.getEndDate()))
.imageUrl(entity.getImage())
.meetingSchedule(StudyMeetingSchedule.builder()
.time(entity.getMeetingTime())
.repetition(meetingRepetitionPersistenceMapper.toDomain(entity.getMeetingRepetition()))
.build())
.meetingSchedule(studyMeetingSchedulePersistenceMapper.toDomain(entity.getMeetingTime(), entity.getMeetingRepetition()))
.isFinished(entity.getIsFinished())
.isDeleted(entity.getIsDeleted())
.build();
Expand All @@ -52,8 +46,7 @@ public StudyJpaEntity toEntity(Study domain) {
.endDate(domain.getEndDate())
.image(domain.getImageUrl())
.meetingTime(domain.getMeetingSchedule().getTime())
.meetingRepetition(
meetingRepetitionPersistenceMapper.toColumn(domain.getMeetingSchedule().getRepetition()))
.meetingRepetition(meetingRepetitionPersistenceMapper.toColumn(domain.getMeetingSchedule().getRepetition()))
.isFinished(domain.isFinished())
.isDeleted(domain.isDeleted())
.build();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,20 +11,18 @@ public class StudyTagPersistenceMapper {

public List<String> toDomains(List<StudyTagJpaEntity> entities) {
return entities != null
? entities.stream()
.map(StudyTagJpaEntity::getName)
.toList()
: List.of();
? entities.stream()
.map(StudyTagJpaEntity::getName)
.toList()
: List.of();
}

public List<StudyTagJpaEntity> toEntities(List<String> domains, Long studyId) {
return !domains.isEmpty()
? domains.stream()
.map(tag -> StudyTagJpaEntity.builder()
.studyId(studyId)
.name(tag)
.build())
.toList()
: List.of();
return domains.stream()
.map(domain -> StudyTagJpaEntity.builder()
.studyId(studyId)
.name(domain)
.build())
.toList();
}
}
Original file line number Diff line number Diff line change
@@ -1,9 +1,8 @@
package com.stumeet.server.study.application.port.in;

import com.stumeet.server.member.domain.Member;
import com.stumeet.server.study.application.port.in.command.StudyCreateCommand;

public interface StudyCreateUseCase {

Long create(StudyCreateCommand command, Member member);
Long create(StudyCreateCommand command, Long memberId);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
package com.stumeet.server.study.application.port.in;

import com.stumeet.server.study.application.port.in.command.StudyUpdateCommand;

public interface StudyUpdateUseCase {

void update(Long studyId, Long memberId, StudyUpdateCommand command);
}
Loading
Loading