From d1480d0ee794d8d1ad6f81811015ca67cc45f996 Mon Sep 17 00:00:00 2001 From: Lee ChanMi Date: Mon, 1 Apr 2024 09:32:55 +0900 Subject: [PATCH 01/35] =?UTF-8?q?:recycle:=20[STMT-62]=20response=20?= =?UTF-8?q?=EC=9C=84=EC=B9=98=EB=A5=BC=20application=EC=9C=BC=EB=A1=9C=20?= =?UTF-8?q?=EB=B3=80=EA=B2=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../com/stumeet/server/study/adapter/in/web/StudyQueryApi.java | 2 +- .../server/study/application/port/in/StudyQueryUseCase.java | 2 +- .../port/in}/response/StudyDetailResponse.java | 2 +- .../study/application/port/out/mapper/StudyUseCaseMapper.java | 2 +- .../server/study/application/service/StudyQueryService.java | 2 +- 5 files changed, 5 insertions(+), 5 deletions(-) rename src/main/java/com/stumeet/server/study/{adapter/in/web => application/port/in}/response/StudyDetailResponse.java (88%) diff --git a/src/main/java/com/stumeet/server/study/adapter/in/web/StudyQueryApi.java b/src/main/java/com/stumeet/server/study/adapter/in/web/StudyQueryApi.java index cd239f72..bf769d9c 100644 --- a/src/main/java/com/stumeet/server/study/adapter/in/web/StudyQueryApi.java +++ b/src/main/java/com/stumeet/server/study/adapter/in/web/StudyQueryApi.java @@ -8,7 +8,7 @@ import com.stumeet.server.common.annotation.WebAdapter; import com.stumeet.server.common.model.ApiResponse; import com.stumeet.server.common.response.SuccessCode; -import com.stumeet.server.study.adapter.in.web.response.StudyDetailResponse; +import com.stumeet.server.study.application.port.in.response.StudyDetailResponse; import com.stumeet.server.study.application.port.in.StudyQueryUseCase; import lombok.RequiredArgsConstructor; diff --git a/src/main/java/com/stumeet/server/study/application/port/in/StudyQueryUseCase.java b/src/main/java/com/stumeet/server/study/application/port/in/StudyQueryUseCase.java index b2972b0f..22a15414 100644 --- a/src/main/java/com/stumeet/server/study/application/port/in/StudyQueryUseCase.java +++ b/src/main/java/com/stumeet/server/study/application/port/in/StudyQueryUseCase.java @@ -1,6 +1,6 @@ package com.stumeet.server.study.application.port.in; -import com.stumeet.server.study.adapter.in.web.response.StudyDetailResponse; +import com.stumeet.server.study.application.port.in.response.StudyDetailResponse; public interface StudyQueryUseCase { diff --git a/src/main/java/com/stumeet/server/study/adapter/in/web/response/StudyDetailResponse.java b/src/main/java/com/stumeet/server/study/application/port/in/response/StudyDetailResponse.java similarity index 88% rename from src/main/java/com/stumeet/server/study/adapter/in/web/response/StudyDetailResponse.java rename to src/main/java/com/stumeet/server/study/application/port/in/response/StudyDetailResponse.java index f714ce5a..a1c1609b 100644 --- a/src/main/java/com/stumeet/server/study/adapter/in/web/response/StudyDetailResponse.java +++ b/src/main/java/com/stumeet/server/study/application/port/in/response/StudyDetailResponse.java @@ -1,4 +1,4 @@ -package com.stumeet.server.study.adapter.in.web.response; +package com.stumeet.server.study.application.port.in.response; import java.time.LocalDateTime; import java.time.LocalTime; diff --git a/src/main/java/com/stumeet/server/study/application/port/out/mapper/StudyUseCaseMapper.java b/src/main/java/com/stumeet/server/study/application/port/out/mapper/StudyUseCaseMapper.java index c9084113..8d4e3308 100644 --- a/src/main/java/com/stumeet/server/study/application/port/out/mapper/StudyUseCaseMapper.java +++ b/src/main/java/com/stumeet/server/study/application/port/out/mapper/StudyUseCaseMapper.java @@ -2,7 +2,7 @@ import org.springframework.stereotype.Component; -import com.stumeet.server.study.adapter.in.web.response.StudyDetailResponse; +import com.stumeet.server.study.application.port.in.response.StudyDetailResponse; import com.stumeet.server.study.domain.Study; @Component diff --git a/src/main/java/com/stumeet/server/study/application/service/StudyQueryService.java b/src/main/java/com/stumeet/server/study/application/service/StudyQueryService.java index 9dc8d25a..615fba6c 100644 --- a/src/main/java/com/stumeet/server/study/application/service/StudyQueryService.java +++ b/src/main/java/com/stumeet/server/study/application/service/StudyQueryService.java @@ -3,7 +3,7 @@ import org.springframework.transaction.annotation.Transactional; import com.stumeet.server.common.annotation.UseCase; -import com.stumeet.server.study.adapter.in.web.response.StudyDetailResponse; +import com.stumeet.server.study.application.port.in.response.StudyDetailResponse; import com.stumeet.server.study.application.port.in.StudyQueryUseCase; import com.stumeet.server.study.application.port.out.StudyQueryPort; import com.stumeet.server.study.application.port.out.mapper.StudyUseCaseMapper; From 613fd27e10c58ae92239087ea4aaacc43b590203 Mon Sep 17 00:00:00 2001 From: Lee ChanMi Date: Mon, 1 Apr 2024 09:51:55 +0900 Subject: [PATCH 02/35] =?UTF-8?q?:recycle:=20[STMT-62]=20usecase=20mapper?= =?UTF-8?q?=20=EC=9C=84=EC=B9=98=EB=A5=BC=20application=20=ED=8C=A8?= =?UTF-8?q?=ED=82=A4=EC=A7=80=EB=A1=9C=20=EB=B3=80=EA=B2=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../application/port/{out => in}/mapper/StudyUseCaseMapper.java | 2 +- .../server/study/application/service/StudyQueryService.java | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) rename src/main/java/com/stumeet/server/study/application/port/{out => in}/mapper/StudyUseCaseMapper.java (93%) diff --git a/src/main/java/com/stumeet/server/study/application/port/out/mapper/StudyUseCaseMapper.java b/src/main/java/com/stumeet/server/study/application/port/in/mapper/StudyUseCaseMapper.java similarity index 93% rename from src/main/java/com/stumeet/server/study/application/port/out/mapper/StudyUseCaseMapper.java rename to src/main/java/com/stumeet/server/study/application/port/in/mapper/StudyUseCaseMapper.java index 8d4e3308..e3d10f4d 100644 --- a/src/main/java/com/stumeet/server/study/application/port/out/mapper/StudyUseCaseMapper.java +++ b/src/main/java/com/stumeet/server/study/application/port/in/mapper/StudyUseCaseMapper.java @@ -1,4 +1,4 @@ -package com.stumeet.server.study.application.port.out.mapper; +package com.stumeet.server.study.application.port.in.mapper; import org.springframework.stereotype.Component; diff --git a/src/main/java/com/stumeet/server/study/application/service/StudyQueryService.java b/src/main/java/com/stumeet/server/study/application/service/StudyQueryService.java index 615fba6c..b29203de 100644 --- a/src/main/java/com/stumeet/server/study/application/service/StudyQueryService.java +++ b/src/main/java/com/stumeet/server/study/application/service/StudyQueryService.java @@ -6,7 +6,7 @@ import com.stumeet.server.study.application.port.in.response.StudyDetailResponse; import com.stumeet.server.study.application.port.in.StudyQueryUseCase; import com.stumeet.server.study.application.port.out.StudyQueryPort; -import com.stumeet.server.study.application.port.out.mapper.StudyUseCaseMapper; +import com.stumeet.server.study.application.port.in.mapper.StudyUseCaseMapper; import com.stumeet.server.study.domain.Study; import lombok.RequiredArgsConstructor; From 299a4b2b8e6dffa23f6fe8c25ea12d0a71425375 Mon Sep 17 00:00:00 2001 From: Lee ChanMi Date: Mon, 1 Apr 2024 10:12:00 +0900 Subject: [PATCH 03/35] =?UTF-8?q?:recycle:=20[STMT-62]=20ScheduleRepetitio?= =?UTF-8?q?nType=20=EC=9D=B4=EB=A6=84=20=EB=B3=80=EA=B2=BD=20->=20Repetiti?= =?UTF-8?q?onType?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../mapper/MeetingRepetitionPersistenceMapper.java | 4 ++-- .../{ScheduleRepetitionType.java => RepetitionType.java} | 2 +- .../com/stumeet/server/study/domain/StudyMeetingSchedule.java | 4 ++-- 3 files changed, 5 insertions(+), 5 deletions(-) rename src/main/java/com/stumeet/server/study/domain/{ScheduleRepetitionType.java => RepetitionType.java} (86%) diff --git a/src/main/java/com/stumeet/server/study/adapter/out/persistance/mapper/MeetingRepetitionPersistenceMapper.java b/src/main/java/com/stumeet/server/study/adapter/out/persistance/mapper/MeetingRepetitionPersistenceMapper.java index 1caac992..e1198548 100644 --- a/src/main/java/com/stumeet/server/study/adapter/out/persistance/mapper/MeetingRepetitionPersistenceMapper.java +++ b/src/main/java/com/stumeet/server/study/adapter/out/persistance/mapper/MeetingRepetitionPersistenceMapper.java @@ -4,7 +4,7 @@ import org.springframework.stereotype.Component; -import com.stumeet.server.study.domain.ScheduleRepetitionType; +import com.stumeet.server.study.domain.RepetitionType; import com.stumeet.server.study.domain.StudyMeetingSchedule; @Component @@ -16,7 +16,7 @@ public StudyMeetingSchedule.Repetition toDomain(String meetingRepetition) { List repetitionElements = List.of(meetingRepetition.split(REPEAT_DELIMITER)); return StudyMeetingSchedule.Repetition.of( - ScheduleRepetitionType.valueOf(repetitionElements.getFirst()), + RepetitionType.valueOf(repetitionElements.getFirst()), repetitionElements.subList(1, repetitionElements.size())); } diff --git a/src/main/java/com/stumeet/server/study/domain/ScheduleRepetitionType.java b/src/main/java/com/stumeet/server/study/domain/RepetitionType.java similarity index 86% rename from src/main/java/com/stumeet/server/study/domain/ScheduleRepetitionType.java rename to src/main/java/com/stumeet/server/study/domain/RepetitionType.java index 8aaaabfd..ba56a1bf 100644 --- a/src/main/java/com/stumeet/server/study/domain/ScheduleRepetitionType.java +++ b/src/main/java/com/stumeet/server/study/domain/RepetitionType.java @@ -4,7 +4,7 @@ import lombok.AllArgsConstructor; @AllArgsConstructor(access = AccessLevel.PRIVATE) -public enum ScheduleRepetitionType { +public enum RepetitionType { DAILY("매일"), WEEKLY("매주"), diff --git a/src/main/java/com/stumeet/server/study/domain/StudyMeetingSchedule.java b/src/main/java/com/stumeet/server/study/domain/StudyMeetingSchedule.java index 27565275..ad6142ca 100644 --- a/src/main/java/com/stumeet/server/study/domain/StudyMeetingSchedule.java +++ b/src/main/java/com/stumeet/server/study/domain/StudyMeetingSchedule.java @@ -18,7 +18,7 @@ public class StudyMeetingSchedule { @AllArgsConstructor(staticName = "of") public static class Repetition { - private final ScheduleRepetitionType type; + private final RepetitionType type; private final List dates; } @@ -31,7 +31,7 @@ public LocalTime getTime() { return time; } - public ScheduleRepetitionType getRepetitionType() { + public RepetitionType getRepetitionType() { return repetition.getType(); } From 4f62d2cc4053c85da43ec801706a3fee1f223a54 Mon Sep 17 00:00:00 2001 From: Lee ChanMi Date: Mon, 1 Apr 2024 20:38:28 +0900 Subject: [PATCH 04/35] =?UTF-8?q?:adhesive=5Fbandage:=20[STMT-62]=20NotExi?= =?UTF-8?q?stException=20=EB=82=B4=EB=B6=80=EC=97=90=20NotFound=20ErrorCod?= =?UTF-8?q?e=20=EB=82=B4=EC=9E=AC=ED=99=94?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../com/stumeet/server/common/response/ErrorCode.java | 1 + .../domain/exception/StudyFieldNotExistsException.java | 10 ++++++++++ .../domain/exception/StudyNotExistsException.java | 4 ++-- 3 files changed, 13 insertions(+), 2 deletions(-) create mode 100644 src/main/java/com/stumeet/server/study/domain/exception/StudyFieldNotExistsException.java diff --git a/src/main/java/com/stumeet/server/common/response/ErrorCode.java b/src/main/java/com/stumeet/server/common/response/ErrorCode.java index 9e5203c1..bb54fa6a 100644 --- a/src/main/java/com/stumeet/server/common/response/ErrorCode.java +++ b/src/main/java/com/stumeet/server/common/response/ErrorCode.java @@ -47,6 +47,7 @@ public enum ErrorCode { */ STUDY_NOT_FOUND(HttpStatus.NOT_FOUND, "존재하지 않는 스터디 입니다."), MEMBER_NOT_FOUND(HttpStatus.NOT_FOUND, "존재하지 않는 멤버 입니다."), + STUDY_FIELD_NOT_FOUND(HttpStatus.NOT_FOUND, "존재하지 않는 스터디 분야 입니다."), /* 500 - INTERNAL SERVER ERROR diff --git a/src/main/java/com/stumeet/server/study/domain/exception/StudyFieldNotExistsException.java b/src/main/java/com/stumeet/server/study/domain/exception/StudyFieldNotExistsException.java new file mode 100644 index 00000000..01b0007a --- /dev/null +++ b/src/main/java/com/stumeet/server/study/domain/exception/StudyFieldNotExistsException.java @@ -0,0 +1,10 @@ +package com.stumeet.server.study.domain.exception; + +import com.stumeet.server.common.exception.model.NotExistsException; +import com.stumeet.server.common.response.ErrorCode; + +public class StudyFieldNotExistsException extends NotExistsException { + public StudyFieldNotExistsException(Long id) { + super("존재하지 않는 스터디 분야입니다. 전달받은 id : " + id, ErrorCode.STUDY_FIELD_NOT_FOUND); + } +} diff --git a/src/main/java/com/stumeet/server/study/domain/exception/StudyNotExistsException.java b/src/main/java/com/stumeet/server/study/domain/exception/StudyNotExistsException.java index e25c8146..f9b122e1 100644 --- a/src/main/java/com/stumeet/server/study/domain/exception/StudyNotExistsException.java +++ b/src/main/java/com/stumeet/server/study/domain/exception/StudyNotExistsException.java @@ -4,7 +4,7 @@ import com.stumeet.server.common.response.ErrorCode; public class StudyNotExistsException extends NotExistsException { - public StudyNotExistsException(Long id, ErrorCode errorCode) { - super("존재하지 않는 스터디입니다. 전달받은 id : " + id, errorCode); + public StudyNotExistsException(Long id) { + super("존재하지 않는 스터디입니다. 전달받은 id : " + id, ErrorCode.STUDY_NOT_FOUND); } } From cde5878dcc31ce6479ca013743db0b60b34f1747 Mon Sep 17 00:00:00 2001 From: Lee ChanMi Date: Mon, 1 Apr 2024 20:46:05 +0900 Subject: [PATCH 05/35] =?UTF-8?q?:sparkles:=20[STMT-62]=20=EC=8A=A4?= =?UTF-8?q?=ED=84=B0=EB=94=94=20=EC=83=9D=EC=84=B1=20=EA=B4=80=EB=A0=A8=20?= =?UTF-8?q?adapter=20=EA=B5=AC=ED=98=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../persistance/JpaStudyDomainRepository.java | 8 +++++ .../persistance/JpaStudyFieldRepository.java | 8 +++++ .../persistance/JpaStudyTagRepository.java | 8 +++++ .../StudyDomainPersistenceAdapter.java | 24 +++++++++++++ .../StudyFieldPersistenceAdapter.java | 34 +++++++++++++++++++ .../persistance/StudyPersistenceAdapter.java | 17 ++++++++-- .../out/persistance/StudyRepository.java | 10 ------ .../out/persistance/StudyRepositoryImpl.java | 27 --------------- .../StudyTagPersistenceAdapter.java | 27 +++++++++++++++ .../entity/StudyDomainJpaEntity.java | 3 +- .../port/out/StudyDomainCommandPort.java | 8 +++++ .../port/out/StudyFieldQueryPort.java | 10 ++++++ 12 files changed, 142 insertions(+), 42 deletions(-) create mode 100644 src/main/java/com/stumeet/server/study/adapter/out/persistance/JpaStudyDomainRepository.java create mode 100644 src/main/java/com/stumeet/server/study/adapter/out/persistance/JpaStudyFieldRepository.java create mode 100644 src/main/java/com/stumeet/server/study/adapter/out/persistance/JpaStudyTagRepository.java create mode 100644 src/main/java/com/stumeet/server/study/adapter/out/persistance/StudyDomainPersistenceAdapter.java create mode 100644 src/main/java/com/stumeet/server/study/adapter/out/persistance/StudyFieldPersistenceAdapter.java delete mode 100644 src/main/java/com/stumeet/server/study/adapter/out/persistance/StudyRepository.java delete mode 100644 src/main/java/com/stumeet/server/study/adapter/out/persistance/StudyRepositoryImpl.java create mode 100644 src/main/java/com/stumeet/server/study/adapter/out/persistance/StudyTagPersistenceAdapter.java create mode 100644 src/main/java/com/stumeet/server/study/application/port/out/StudyDomainCommandPort.java create mode 100644 src/main/java/com/stumeet/server/study/application/port/out/StudyFieldQueryPort.java diff --git a/src/main/java/com/stumeet/server/study/adapter/out/persistance/JpaStudyDomainRepository.java b/src/main/java/com/stumeet/server/study/adapter/out/persistance/JpaStudyDomainRepository.java new file mode 100644 index 00000000..763660d3 --- /dev/null +++ b/src/main/java/com/stumeet/server/study/adapter/out/persistance/JpaStudyDomainRepository.java @@ -0,0 +1,8 @@ +package com.stumeet.server.study.adapter.out.persistance; + +import org.springframework.data.jpa.repository.JpaRepository; + +import com.stumeet.server.study.adapter.out.persistance.entity.StudyDomainJpaEntity; + +public interface JpaStudyDomainRepository extends JpaRepository { +} diff --git a/src/main/java/com/stumeet/server/study/adapter/out/persistance/JpaStudyFieldRepository.java b/src/main/java/com/stumeet/server/study/adapter/out/persistance/JpaStudyFieldRepository.java new file mode 100644 index 00000000..4ee41ef1 --- /dev/null +++ b/src/main/java/com/stumeet/server/study/adapter/out/persistance/JpaStudyFieldRepository.java @@ -0,0 +1,8 @@ +package com.stumeet.server.study.adapter.out.persistance; + +import org.springframework.data.jpa.repository.JpaRepository; + +import com.stumeet.server.study.adapter.out.persistance.entity.StudyFieldJpaEntity; + +public interface JpaStudyFieldRepository extends JpaRepository { +} diff --git a/src/main/java/com/stumeet/server/study/adapter/out/persistance/JpaStudyTagRepository.java b/src/main/java/com/stumeet/server/study/adapter/out/persistance/JpaStudyTagRepository.java new file mode 100644 index 00000000..737c54e8 --- /dev/null +++ b/src/main/java/com/stumeet/server/study/adapter/out/persistance/JpaStudyTagRepository.java @@ -0,0 +1,8 @@ +package com.stumeet.server.study.adapter.out.persistance; + +import org.springframework.data.jpa.repository.JpaRepository; + +import com.stumeet.server.study.adapter.out.persistance.entity.StudyTagJpaEntity; + +public interface JpaStudyTagRepository extends JpaRepository { +} diff --git a/src/main/java/com/stumeet/server/study/adapter/out/persistance/StudyDomainPersistenceAdapter.java b/src/main/java/com/stumeet/server/study/adapter/out/persistance/StudyDomainPersistenceAdapter.java new file mode 100644 index 00000000..27fa63c7 --- /dev/null +++ b/src/main/java/com/stumeet/server/study/adapter/out/persistance/StudyDomainPersistenceAdapter.java @@ -0,0 +1,24 @@ +package com.stumeet.server.study.adapter.out.persistance; + +import com.stumeet.server.common.annotation.PersistenceAdapter; +import com.stumeet.server.study.adapter.out.persistance.entity.StudyDomainJpaEntity; +import com.stumeet.server.study.adapter.out.persistance.mapper.StudyDomainPersistenceMapper; +import com.stumeet.server.study.application.port.out.StudyDomainCommandPort; +import com.stumeet.server.study.domain.StudyDomain; + +import lombok.RequiredArgsConstructor; + +@PersistenceAdapter +@RequiredArgsConstructor +public class StudyDomainPersistenceAdapter implements StudyDomainCommandPort { + + private final JpaStudyDomainRepository studyDomainRepository; + private final StudyDomainPersistenceMapper studyDomainPersistenceMapper; + + @Override + public StudyDomain save(StudyDomain studyDomain) { + StudyDomainJpaEntity entity = studyDomainRepository.save(studyDomainPersistenceMapper.toEntity(studyDomain)); + + return studyDomainPersistenceMapper.toDomain(entity); + } +} diff --git a/src/main/java/com/stumeet/server/study/adapter/out/persistance/StudyFieldPersistenceAdapter.java b/src/main/java/com/stumeet/server/study/adapter/out/persistance/StudyFieldPersistenceAdapter.java new file mode 100644 index 00000000..25fcc024 --- /dev/null +++ b/src/main/java/com/stumeet/server/study/adapter/out/persistance/StudyFieldPersistenceAdapter.java @@ -0,0 +1,34 @@ +package com.stumeet.server.study.adapter.out.persistance; + +import com.stumeet.server.common.annotation.PersistenceAdapter; +import com.stumeet.server.study.adapter.out.persistance.entity.StudyFieldJpaEntity; +import com.stumeet.server.study.adapter.out.persistance.mapper.StudyFieldPersistenceMapper; +import com.stumeet.server.study.application.port.out.StudyFieldQueryPort; +import com.stumeet.server.study.domain.StudyField; +import com.stumeet.server.study.domain.exception.StudyFieldNotExistsException; + +import lombok.AccessLevel; +import lombok.RequiredArgsConstructor; + +@PersistenceAdapter +@RequiredArgsConstructor(access = AccessLevel.PRIVATE) +public class StudyFieldPersistenceAdapter implements StudyFieldQueryPort { + + private final JpaStudyFieldRepository studyFieldRepository; + private final StudyFieldPersistenceMapper studyFieldPersistenceMapper; + + @Override + public void checkById(Long id) { + if (!studyFieldRepository.existsById(id)) { + throw new StudyFieldNotExistsException(id); + } + } + + @Override + public StudyField getById(Long id) { + StudyFieldJpaEntity entity = studyFieldRepository.findById(id) + .orElseThrow(() -> new StudyFieldNotExistsException(id)); + + return studyFieldPersistenceMapper.toDomain(entity); + } +} diff --git a/src/main/java/com/stumeet/server/study/adapter/out/persistance/StudyPersistenceAdapter.java b/src/main/java/com/stumeet/server/study/adapter/out/persistance/StudyPersistenceAdapter.java index 3183618d..beac4ecb 100644 --- a/src/main/java/com/stumeet/server/study/adapter/out/persistance/StudyPersistenceAdapter.java +++ b/src/main/java/com/stumeet/server/study/adapter/out/persistance/StudyPersistenceAdapter.java @@ -3,22 +3,26 @@ import com.stumeet.server.common.annotation.PersistenceAdapter; import com.stumeet.server.study.adapter.out.persistance.entity.StudyJpaEntity; import com.stumeet.server.study.adapter.out.persistance.mapper.StudyPersistenceMapper; +import com.stumeet.server.study.application.port.out.StudyCommandPort; 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; @PersistenceAdapter @RequiredArgsConstructor -public class StudyPersistenceAdapter implements StudyQueryPort, StudyValidationPort { +public class StudyPersistenceAdapter implements StudyQueryPort, StudyValidationPort, StudyCommandPort { - private final StudyRepository studyRepository; + private final JpaStudyRepository studyRepository; private final StudyPersistenceMapper studyPersistenceMapper; @Override public Study getById(Long id) { - StudyJpaEntity entity = studyRepository.findById(id); + StudyJpaEntity entity = studyRepository.findById(id) + .orElseThrow(() -> new StudyNotExistsException(id)); + return studyPersistenceMapper.toDomain(entity); } @@ -26,4 +30,11 @@ public Study getById(Long id) { public boolean existsById(Long id) { return studyRepository.existsById(id); } + + @Override + public Study save(Study study) { + StudyJpaEntity entity = studyRepository.save(studyPersistenceMapper.toEntity(study)); + + return studyPersistenceMapper.toDomain(entity); + } } diff --git a/src/main/java/com/stumeet/server/study/adapter/out/persistance/StudyRepository.java b/src/main/java/com/stumeet/server/study/adapter/out/persistance/StudyRepository.java deleted file mode 100644 index 03a1ead3..00000000 --- a/src/main/java/com/stumeet/server/study/adapter/out/persistance/StudyRepository.java +++ /dev/null @@ -1,10 +0,0 @@ -package com.stumeet.server.study.adapter.out.persistance; - -import com.stumeet.server.study.adapter.out.persistance.entity.StudyJpaEntity; - -public interface StudyRepository { - - StudyJpaEntity findById(Long id); - - boolean existsById(Long id); -} diff --git a/src/main/java/com/stumeet/server/study/adapter/out/persistance/StudyRepositoryImpl.java b/src/main/java/com/stumeet/server/study/adapter/out/persistance/StudyRepositoryImpl.java deleted file mode 100644 index f4249d72..00000000 --- a/src/main/java/com/stumeet/server/study/adapter/out/persistance/StudyRepositoryImpl.java +++ /dev/null @@ -1,27 +0,0 @@ -package com.stumeet.server.study.adapter.out.persistance; - -import org.springframework.stereotype.Repository; - -import com.stumeet.server.common.exception.model.BusinessException; -import com.stumeet.server.common.response.ErrorCode; -import com.stumeet.server.study.adapter.out.persistance.entity.StudyJpaEntity; - -import lombok.RequiredArgsConstructor; - -@Repository -@RequiredArgsConstructor -public class StudyRepositoryImpl implements StudyRepository { - - private final JpaStudyRepository jpaStudyRepository; - - @Override - public StudyJpaEntity findById(Long id) { - return jpaStudyRepository.findById(id) - .orElseThrow(() -> new BusinessException(ErrorCode.STUDY_NOT_FOUND)); - } - - @Override - public boolean existsById(Long id) { - return jpaStudyRepository.existsById(id); - } -} diff --git a/src/main/java/com/stumeet/server/study/adapter/out/persistance/StudyTagPersistenceAdapter.java b/src/main/java/com/stumeet/server/study/adapter/out/persistance/StudyTagPersistenceAdapter.java new file mode 100644 index 00000000..b7ba204f --- /dev/null +++ b/src/main/java/com/stumeet/server/study/adapter/out/persistance/StudyTagPersistenceAdapter.java @@ -0,0 +1,27 @@ +package com.stumeet.server.study.adapter.out.persistance; + +import java.util.List; + +import com.stumeet.server.common.annotation.PersistenceAdapter; +import com.stumeet.server.study.adapter.out.persistance.entity.StudyTagJpaEntity; +import com.stumeet.server.study.adapter.out.persistance.mapper.StudyTagPersistenceMapper; +import com.stumeet.server.study.application.port.out.StudyTagCommandPort; +import com.stumeet.server.study.domain.StudyTag; + +import lombok.RequiredArgsConstructor; + +@PersistenceAdapter +@RequiredArgsConstructor +public class StudyTagPersistenceAdapter implements StudyTagCommandPort { + + private final JpaStudyTagRepository studyTagRepository; + private final StudyTagPersistenceMapper studyTagPersistenceMapper; + + @Override + public List saveAll(List studyTags, Long studyDomainId) { + List entities = + studyTagRepository.saveAll(studyTagPersistenceMapper.toEntities(studyTags, studyDomainId)); + + return studyTagPersistenceMapper.toDomains(entities); + } +} diff --git a/src/main/java/com/stumeet/server/study/adapter/out/persistance/entity/StudyDomainJpaEntity.java b/src/main/java/com/stumeet/server/study/adapter/out/persistance/entity/StudyDomainJpaEntity.java index 4346ae6e..cc0c5995 100644 --- a/src/main/java/com/stumeet/server/study/adapter/out/persistance/entity/StudyDomainJpaEntity.java +++ b/src/main/java/com/stumeet/server/study/adapter/out/persistance/entity/StudyDomainJpaEntity.java @@ -4,7 +4,6 @@ import org.hibernate.annotations.Comment; -import jakarta.persistence.CascadeType; import jakarta.persistence.Entity; import jakarta.persistence.GeneratedValue; import jakarta.persistence.GenerationType; @@ -37,7 +36,7 @@ public class StudyDomainJpaEntity { @Comment("분야") private StudyFieldJpaEntity studyField; - @OneToMany(cascade = CascadeType.ALL, orphanRemoval = true) + @OneToMany(orphanRemoval = true) @JoinColumn(name = "study_domain_id") private List studyTags; } diff --git a/src/main/java/com/stumeet/server/study/application/port/out/StudyDomainCommandPort.java b/src/main/java/com/stumeet/server/study/application/port/out/StudyDomainCommandPort.java new file mode 100644 index 00000000..c09f24ba --- /dev/null +++ b/src/main/java/com/stumeet/server/study/application/port/out/StudyDomainCommandPort.java @@ -0,0 +1,8 @@ +package com.stumeet.server.study.application.port.out; + +import com.stumeet.server.study.domain.StudyDomain; + +public interface StudyDomainCommandPort { + + StudyDomain save(StudyDomain studyDomain); +} diff --git a/src/main/java/com/stumeet/server/study/application/port/out/StudyFieldQueryPort.java b/src/main/java/com/stumeet/server/study/application/port/out/StudyFieldQueryPort.java new file mode 100644 index 00000000..03d6b6a1 --- /dev/null +++ b/src/main/java/com/stumeet/server/study/application/port/out/StudyFieldQueryPort.java @@ -0,0 +1,10 @@ +package com.stumeet.server.study.application.port.out; + +import com.stumeet.server.study.domain.StudyField; + +public interface StudyFieldQueryPort { + + void checkById(Long id); + + StudyField getById(Long id); +} From f5286aa2206ef85c548cf41e84afe7d335b97973 Mon Sep 17 00:00:00 2001 From: Lee ChanMi Date: Mon, 1 Apr 2024 20:47:17 +0900 Subject: [PATCH 06/35] =?UTF-8?q?:sparkles:=20[STMT-62]=20=EC=8A=A4?= =?UTF-8?q?=ED=84=B0=EB=94=94=20=EB=A9=94=EC=9D=B8=20=EC=9D=B4=EB=AF=B8?= =?UTF-8?q?=EC=A7=80=20=EC=97=85=EB=A1=9C=EB=93=9C=20=EA=B8=B0=EB=8A=A5=20?= =?UTF-8?q?=EA=B5=AC=ED=98=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../server/file/application/port/in/FileUploadUseCase.java | 2 ++ .../server/file/application/service/FileUploadService.java | 6 ++++++ 2 files changed, 8 insertions(+) diff --git a/src/main/java/com/stumeet/server/file/application/port/in/FileUploadUseCase.java b/src/main/java/com/stumeet/server/file/application/port/in/FileUploadUseCase.java index 12496fb6..4e919a25 100644 --- a/src/main/java/com/stumeet/server/file/application/port/in/FileUploadUseCase.java +++ b/src/main/java/com/stumeet/server/file/application/port/in/FileUploadUseCase.java @@ -9,5 +9,7 @@ public interface FileUploadUseCase { FileUrl uploadUserProfileImage(Long userId, MultipartFile multipartFile); + FileUrl uploadStudyMainImage(MultipartFile multipartFile); + List uploadStudyActivityImage(Long studyId, List multipartFile); } diff --git a/src/main/java/com/stumeet/server/file/application/service/FileUploadService.java b/src/main/java/com/stumeet/server/file/application/service/FileUploadService.java index a7569955..88bfae6a 100644 --- a/src/main/java/com/stumeet/server/file/application/service/FileUploadService.java +++ b/src/main/java/com/stumeet/server/file/application/service/FileUploadService.java @@ -16,6 +16,7 @@ public class FileUploadService implements FileUploadUseCase { private static final String USER_PROFILE_IMAGE_DIRECTORY_PATH = "user/%d/profile"; + private static final String STUDY_MAIN_IMAGE_DIRECTORY_PATH = "study/main"; private static final String STUDY_ACTIVITY_IMAGE_DIRECTORY_PATH = "study/%d/activity"; private final FileCommandPort fileCommandPort; @@ -27,6 +28,11 @@ public FileUrl uploadUserProfileImage(Long userId, MultipartFile multipartFile) return fileCommandPort.uploadImageFile(multipartFile, path); } + @Override + public FileUrl uploadStudyMainImage(MultipartFile multipartFile) { + return fileCommandPort.uploadImageFile(multipartFile, STUDY_MAIN_IMAGE_DIRECTORY_PATH); + } + @Override public List uploadStudyActivityImage(Long studyId, List multipartFiles) { String path = String.format(STUDY_ACTIVITY_IMAGE_DIRECTORY_PATH, studyId); From f44a76f639dba80c6a668a4780f46989578819ab Mon Sep 17 00:00:00 2001 From: Lee ChanMi Date: Mon, 1 Apr 2024 20:48:22 +0900 Subject: [PATCH 07/35] =?UTF-8?q?:sparkles:=20[STMT-62]=20=EC=8A=A4?= =?UTF-8?q?=ED=84=B0=EB=94=94=20=EC=83=9D=EC=84=B1=20=EA=B8=B0=EB=8A=A5=20?= =?UTF-8?q?=EA=B5=AC=ED=98=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../study/adapter/in/web/StudyCreateApi.java | 42 ++++++++++ .../port/in/StudyCreateUseCase.java | 11 +++ .../port/in/command/StudyCreateCommand.java | 33 ++++++++ .../mapper/MeetingScheduleUseCaseMapper.java | 18 ++++ .../in/mapper/StudyDomainUseCaseMapper.java | 23 ++++++ .../in/mapper/StudyFieldUseCaseMapper.java | 15 ++++ .../in/mapper/StudyTagsUseCaseMapper.java | 23 ++++++ .../port/out/StudyCommandPort.java | 8 ++ .../port/out/StudyTagCommandPort.java | 10 +++ .../service/StudyCreateService.java | 82 +++++++++++++++++++ .../service/StudyQueryService.java | 2 +- .../service/StudyValidationService.java | 3 +- 12 files changed, 267 insertions(+), 3 deletions(-) create mode 100644 src/main/java/com/stumeet/server/study/adapter/in/web/StudyCreateApi.java create mode 100644 src/main/java/com/stumeet/server/study/application/port/in/StudyCreateUseCase.java create mode 100644 src/main/java/com/stumeet/server/study/application/port/in/command/StudyCreateCommand.java create mode 100644 src/main/java/com/stumeet/server/study/application/port/in/mapper/MeetingScheduleUseCaseMapper.java create mode 100644 src/main/java/com/stumeet/server/study/application/port/in/mapper/StudyDomainUseCaseMapper.java create mode 100644 src/main/java/com/stumeet/server/study/application/port/in/mapper/StudyFieldUseCaseMapper.java create mode 100644 src/main/java/com/stumeet/server/study/application/port/in/mapper/StudyTagsUseCaseMapper.java create mode 100644 src/main/java/com/stumeet/server/study/application/port/out/StudyCommandPort.java create mode 100644 src/main/java/com/stumeet/server/study/application/port/out/StudyTagCommandPort.java create mode 100644 src/main/java/com/stumeet/server/study/application/service/StudyCreateService.java diff --git a/src/main/java/com/stumeet/server/study/adapter/in/web/StudyCreateApi.java b/src/main/java/com/stumeet/server/study/adapter/in/web/StudyCreateApi.java new file mode 100644 index 00000000..7775ae77 --- /dev/null +++ b/src/main/java/com/stumeet/server/study/adapter/in/web/StudyCreateApi.java @@ -0,0 +1,42 @@ +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.PostMapping; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RequestPart; +import org.springframework.web.multipart.MultipartFile; + +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.study.application.port.in.StudyCreateUseCase; +import com.stumeet.server.study.application.port.in.StudyQueryUseCase; +import com.stumeet.server.study.application.port.in.command.StudyCreateCommand; +import com.stumeet.server.study.application.port.in.response.StudyDetailResponse; + +import lombok.RequiredArgsConstructor; + +@WebAdapter +@RequestMapping("/api/v1/studies") +@RequiredArgsConstructor +public class StudyCreateApi { + + private final StudyCreateUseCase studyCreateUseCase; + private final StudyQueryUseCase studyQueryUseCase; + + @PostMapping(consumes = "multipart/form-data", produces = "application/json") + public ResponseEntity> create( + @AuthenticationPrincipal LoginMember member, + @RequestPart StudyCreateCommand request, + @RequestPart MultipartFile studyMainImage + ) { + Long createdStudyId = studyCreateUseCase.create(request, member.getMember(), studyMainImage); + StudyDetailResponse response = studyQueryUseCase.getStudyDetailById(createdStudyId); + + return new ResponseEntity<>( + ApiResponse.success(HttpStatus.CREATED.value(), "스터디 그룹 생성에 성공했습니다.", response), + HttpStatus.CREATED); + } +} diff --git a/src/main/java/com/stumeet/server/study/application/port/in/StudyCreateUseCase.java b/src/main/java/com/stumeet/server/study/application/port/in/StudyCreateUseCase.java new file mode 100644 index 00000000..52f9b054 --- /dev/null +++ b/src/main/java/com/stumeet/server/study/application/port/in/StudyCreateUseCase.java @@ -0,0 +1,11 @@ +package com.stumeet.server.study.application.port.in; + +import org.springframework.web.multipart.MultipartFile; + +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, MultipartFile mainImage); +} diff --git a/src/main/java/com/stumeet/server/study/application/port/in/command/StudyCreateCommand.java b/src/main/java/com/stumeet/server/study/application/port/in/command/StudyCreateCommand.java new file mode 100644 index 00000000..afe6ea03 --- /dev/null +++ b/src/main/java/com/stumeet/server/study/application/port/in/command/StudyCreateCommand.java @@ -0,0 +1,33 @@ +package com.stumeet.server.study.application.port.in.command; + +import java.time.LocalDateTime; +import java.time.LocalTime; +import java.util.List; + +import com.stumeet.server.study.domain.RepetitionType; + +import jakarta.validation.constraints.NotBlank; +import jakarta.validation.constraints.NotNull; + +public record StudyCreateCommand( + @NotNull + Long studyFieldId, + @NotBlank + String name, + @NotBlank + String intro, + @NotBlank + String region, + String rule, + @NotNull + LocalDateTime startDate, + @NotNull + LocalDateTime endDate, + @NotNull + LocalTime meetingTime, + @NotNull + RepetitionType meetingRepetitionType, + List meetingRepetitionDates, + List studyTags +) { +} diff --git a/src/main/java/com/stumeet/server/study/application/port/in/mapper/MeetingScheduleUseCaseMapper.java b/src/main/java/com/stumeet/server/study/application/port/in/mapper/MeetingScheduleUseCaseMapper.java new file mode 100644 index 00000000..f0fddac4 --- /dev/null +++ b/src/main/java/com/stumeet/server/study/application/port/in/mapper/MeetingScheduleUseCaseMapper.java @@ -0,0 +1,18 @@ +package com.stumeet.server.study.application.port.in.mapper; + +import org.springframework.stereotype.Component; + +import com.stumeet.server.study.application.port.in.command.StudyCreateCommand; +import com.stumeet.server.study.domain.StudyMeetingSchedule; + +@Component +public class MeetingScheduleUseCaseMapper { + + public StudyMeetingSchedule toDomain(StudyCreateCommand command) { + return StudyMeetingSchedule.of( + command.meetingTime(), + StudyMeetingSchedule.Repetition.of( + command.meetingRepetitionType(), + command.meetingRepetitionDates())); + } +} \ No newline at end of file diff --git a/src/main/java/com/stumeet/server/study/application/port/in/mapper/StudyDomainUseCaseMapper.java b/src/main/java/com/stumeet/server/study/application/port/in/mapper/StudyDomainUseCaseMapper.java new file mode 100644 index 00000000..8b958bc6 --- /dev/null +++ b/src/main/java/com/stumeet/server/study/application/port/in/mapper/StudyDomainUseCaseMapper.java @@ -0,0 +1,23 @@ +package com.stumeet.server.study.application.port.in.mapper; + +import org.springframework.stereotype.Component; + +import com.stumeet.server.study.application.port.in.command.StudyCreateCommand; +import com.stumeet.server.study.domain.StudyDomain; + +import lombok.RequiredArgsConstructor; + +@Component +@RequiredArgsConstructor +public class StudyDomainUseCaseMapper { + + private final StudyFieldUseCaseMapper studyFieldUseCaseMapper; + private final StudyTagsUseCaseMapper studyTagsUseCaseMapper; + + public StudyDomain toDomain(StudyCreateCommand command) { + return StudyDomain.builder() + .studyField(studyFieldUseCaseMapper.toDomain(command.studyFieldId())) + .studyTags(studyTagsUseCaseMapper.toDomains(command.studyTags())) + .build(); + } +} diff --git a/src/main/java/com/stumeet/server/study/application/port/in/mapper/StudyFieldUseCaseMapper.java b/src/main/java/com/stumeet/server/study/application/port/in/mapper/StudyFieldUseCaseMapper.java new file mode 100644 index 00000000..0bbc4e81 --- /dev/null +++ b/src/main/java/com/stumeet/server/study/application/port/in/mapper/StudyFieldUseCaseMapper.java @@ -0,0 +1,15 @@ +package com.stumeet.server.study.application.port.in.mapper; + +import org.springframework.stereotype.Component; + +import com.stumeet.server.study.domain.StudyField; + +@Component +public class StudyFieldUseCaseMapper { + + public StudyField toDomain(Long studyFieldId) { + return StudyField.builder() + .id(studyFieldId) + .build(); + } +} diff --git a/src/main/java/com/stumeet/server/study/application/port/in/mapper/StudyTagsUseCaseMapper.java b/src/main/java/com/stumeet/server/study/application/port/in/mapper/StudyTagsUseCaseMapper.java new file mode 100644 index 00000000..000fd00e --- /dev/null +++ b/src/main/java/com/stumeet/server/study/application/port/in/mapper/StudyTagsUseCaseMapper.java @@ -0,0 +1,23 @@ +package com.stumeet.server.study.application.port.in.mapper; + +import java.util.List; + +import org.springframework.stereotype.Component; + +import com.stumeet.server.study.domain.StudyTag; + +@Component +public class StudyTagsUseCaseMapper { + + public List toDomains(List tags) { + return tags.stream() + .map(this::toDomain) + .toList(); + } + + private StudyTag toDomain(String tag) { + return StudyTag.builder() + .name(tag) + .build(); + } +} diff --git a/src/main/java/com/stumeet/server/study/application/port/out/StudyCommandPort.java b/src/main/java/com/stumeet/server/study/application/port/out/StudyCommandPort.java new file mode 100644 index 00000000..63b1fc80 --- /dev/null +++ b/src/main/java/com/stumeet/server/study/application/port/out/StudyCommandPort.java @@ -0,0 +1,8 @@ +package com.stumeet.server.study.application.port.out; + +import com.stumeet.server.study.domain.Study; + +public interface StudyCommandPort { + + Study save(Study study); +} diff --git a/src/main/java/com/stumeet/server/study/application/port/out/StudyTagCommandPort.java b/src/main/java/com/stumeet/server/study/application/port/out/StudyTagCommandPort.java new file mode 100644 index 00000000..dd2fa30f --- /dev/null +++ b/src/main/java/com/stumeet/server/study/application/port/out/StudyTagCommandPort.java @@ -0,0 +1,10 @@ +package com.stumeet.server.study.application.port.out; + +import java.util.List; + +import com.stumeet.server.study.domain.StudyTag; + +public interface StudyTagCommandPort { + + List saveAll(List studyTags, Long studyDomainId); +} diff --git a/src/main/java/com/stumeet/server/study/application/service/StudyCreateService.java b/src/main/java/com/stumeet/server/study/application/service/StudyCreateService.java new file mode 100644 index 00000000..d751dd19 --- /dev/null +++ b/src/main/java/com/stumeet/server/study/application/service/StudyCreateService.java @@ -0,0 +1,82 @@ +package com.stumeet.server.study.application.service; + +import org.springframework.transaction.annotation.Transactional; +import org.springframework.web.multipart.MultipartFile; + +import com.stumeet.server.common.annotation.UseCase; +import com.stumeet.server.file.application.port.in.FileUploadUseCase; +import com.stumeet.server.member.domain.Member; +import com.stumeet.server.study.application.port.in.StudyCreateUseCase; +import com.stumeet.server.study.application.port.in.command.StudyCreateCommand; +import com.stumeet.server.study.application.port.in.mapper.MeetingScheduleUseCaseMapper; +import com.stumeet.server.study.application.port.in.mapper.StudyDomainUseCaseMapper; +import com.stumeet.server.study.application.port.out.StudyCommandPort; +import com.stumeet.server.study.application.port.out.StudyDomainCommandPort; +import com.stumeet.server.study.application.port.out.StudyFieldQueryPort; +import com.stumeet.server.study.application.port.out.StudyTagCommandPort; +import com.stumeet.server.study.domain.Study; +import com.stumeet.server.study.domain.StudyDomain; +import com.stumeet.server.study.domain.StudyHeadCount; +import com.stumeet.server.study.domain.StudyPeriod; +import com.stumeet.server.studymember.application.port.in.StudyMemberJoinUseCase; +import com.stumeet.server.studymember.application.port.in.command.StudyMemberJoinCommand; + +import lombok.RequiredArgsConstructor; + +@UseCase +@RequiredArgsConstructor +public class StudyCreateService implements StudyCreateUseCase { + + private final FileUploadUseCase fileUploadUseCase; + private final StudyMemberJoinUseCase memberJoinUseCase; + + private final StudyCommandPort studyCommandPort; + private final StudyFieldQueryPort studyFieldQueryPort; + private final StudyDomainCommandPort studyDomainCommandPort; + private final StudyTagCommandPort studyTagCommandPort; + + private final StudyDomainUseCaseMapper studyDomainUseCaseMapper; + private final MeetingScheduleUseCaseMapper meetingScheduleUseCaseMapper; + + @Override + @Transactional + public Long create(StudyCreateCommand command, Member member, MultipartFile mainImage) { + studyFieldQueryPort.checkById(command.studyFieldId()); + + StudyDomain studyDomainCreated = createStudyDomain(studyDomainUseCaseMapper.toDomain(command)); + String mainImageUrl = fileUploadUseCase.uploadStudyMainImage(mainImage).url(); + + Study study = Study.builder() + .studyDomain(studyDomainCreated) + .name(command.name()) + .intro(command.intro()) + .rule(command.rule()) + .region(command.region()) + .period(StudyPeriod.of(command.startDate(), command.endDate())) + .meetingSchedule(meetingScheduleUseCaseMapper.toDomain(command)) + .headcount(StudyHeadCount.from(1)) + .image(mainImageUrl) + .isFinished(false) + .isDeleted(false) + .build(); + + Study studyCreated = studyCommandPort.save(study); + + StudyMemberJoinCommand studyMemberJoinCommand = StudyMemberJoinCommand.builder() + .memberId(member.getId()) + .studyId(studyCreated.getId()) + .isAdmin(true) + .build(); + + memberJoinUseCase.join(studyMemberJoinCommand); + + return studyCreated.getId(); + } + + private StudyDomain createStudyDomain(StudyDomain studyDomain) { + StudyDomain created = studyDomainCommandPort.save(studyDomain); + studyTagCommandPort.saveAll(created.getStudyTags(), created.getId()); + + return created; + } +} diff --git a/src/main/java/com/stumeet/server/study/application/service/StudyQueryService.java b/src/main/java/com/stumeet/server/study/application/service/StudyQueryService.java index b29203de..273f1007 100644 --- a/src/main/java/com/stumeet/server/study/application/service/StudyQueryService.java +++ b/src/main/java/com/stumeet/server/study/application/service/StudyQueryService.java @@ -20,7 +20,7 @@ public class StudyQueryService implements StudyQueryUseCase { private final StudyUseCaseMapper studyUseCaseMapper; @Override - public StudyDetailResponse getStudyDetailById(Long id) { + public StudyDetailResponse getStudyDetailById(java.lang.Long id) { Study study = studyQueryPort.getById(id); return studyUseCaseMapper.toStudyDetailResponse(study); } diff --git a/src/main/java/com/stumeet/server/study/application/service/StudyValidationService.java b/src/main/java/com/stumeet/server/study/application/service/StudyValidationService.java index 7f2902a0..215e2c25 100644 --- a/src/main/java/com/stumeet/server/study/application/service/StudyValidationService.java +++ b/src/main/java/com/stumeet/server/study/application/service/StudyValidationService.java @@ -1,7 +1,6 @@ package com.stumeet.server.study.application.service; import com.stumeet.server.common.annotation.UseCase; -import com.stumeet.server.common.response.ErrorCode; import com.stumeet.server.study.application.port.in.StudyValidationUseCase; import com.stumeet.server.study.application.port.out.StudyValidationPort; import com.stumeet.server.study.domain.exception.StudyNotExistsException; @@ -18,7 +17,7 @@ public class StudyValidationService implements StudyValidationUseCase { @Override public void checkById(Long id) { if (!studyValidationPort.existsById(id)) { - throw new StudyNotExistsException(id, ErrorCode.STUDY_NOT_FOUND); + throw new StudyNotExistsException(id); } } } From 3602f2e9d5c771a180bf7b026ff3ae7c076c5fe1 Mon Sep 17 00:00:00 2001 From: Lee ChanMi Date: Mon, 1 Apr 2024 20:49:06 +0900 Subject: [PATCH 08/35] =?UTF-8?q?:sparkles:=20[STMT-62]=20=EC=8A=A4?= =?UTF-8?q?=ED=84=B0=EB=94=94=20=EC=BF=BC=EB=A6=AC=20=EB=B3=80=EC=88=98?= =?UTF-8?q?=EB=AA=85=20=EB=B3=80=EA=B2=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../server/study/adapter/in/web/StudyQueryApi.java | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/main/java/com/stumeet/server/study/adapter/in/web/StudyQueryApi.java b/src/main/java/com/stumeet/server/study/adapter/in/web/StudyQueryApi.java index bf769d9c..15055de7 100644 --- a/src/main/java/com/stumeet/server/study/adapter/in/web/StudyQueryApi.java +++ b/src/main/java/com/stumeet/server/study/adapter/in/web/StudyQueryApi.java @@ -20,11 +20,11 @@ public class StudyQueryApi { private final StudyQueryUseCase studyQueryUseCase; - @GetMapping("/{id}") - public ResponseEntity> getStudy( - @PathVariable(name = "id") Long id + @GetMapping("/{studyId}") + public ResponseEntity> getStudyDetail( + @PathVariable(name = "studyId") java.lang.Long studyId ) { - StudyDetailResponse response = studyQueryUseCase.getStudyDetailById(id); + StudyDetailResponse response = studyQueryUseCase.getStudyDetailById(studyId); return ResponseEntity.ok(ApiResponse.success(SuccessCode.GET_SUCCESS, response)); } } From c387c8247acc40bbd5dda4edde043b10fab933fa Mon Sep 17 00:00:00 2001 From: Lee ChanMi Date: Tue, 2 Apr 2024 11:43:41 +0900 Subject: [PATCH 09/35] =?UTF-8?q?:sparkles:=20[STMT-62]=20=EC=9A=94?= =?UTF-8?q?=EC=B2=AD=20=EB=B3=80=EC=88=98=20=EA=B2=80=EC=A6=9D=20=EB=A9=94?= =?UTF-8?q?=EC=8B=9C=EC=A7=80=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../study/adapter/in/web/StudyCreateApi.java | 8 ++--- .../port/in/StudyCreateUseCase.java | 4 +-- .../port/in/command/StudyCreateCommand.java | 30 ++++++++++++------- .../server/study/domain/StudyPeriod.java | 8 ++--- 4 files changed, 27 insertions(+), 23 deletions(-) diff --git a/src/main/java/com/stumeet/server/study/adapter/in/web/StudyCreateApi.java b/src/main/java/com/stumeet/server/study/adapter/in/web/StudyCreateApi.java index 7775ae77..22bf56ea 100644 --- a/src/main/java/com/stumeet/server/study/adapter/in/web/StudyCreateApi.java +++ b/src/main/java/com/stumeet/server/study/adapter/in/web/StudyCreateApi.java @@ -5,8 +5,6 @@ import org.springframework.security.core.annotation.AuthenticationPrincipal; import org.springframework.web.bind.annotation.PostMapping; import org.springframework.web.bind.annotation.RequestMapping; -import org.springframework.web.bind.annotation.RequestPart; -import org.springframework.web.multipart.MultipartFile; import com.stumeet.server.common.annotation.WebAdapter; import com.stumeet.server.common.auth.model.LoginMember; @@ -16,6 +14,7 @@ import com.stumeet.server.study.application.port.in.command.StudyCreateCommand; import com.stumeet.server.study.application.port.in.response.StudyDetailResponse; +import jakarta.validation.Valid; import lombok.RequiredArgsConstructor; @WebAdapter @@ -29,10 +28,9 @@ public class StudyCreateApi { @PostMapping(consumes = "multipart/form-data", produces = "application/json") public ResponseEntity> create( @AuthenticationPrincipal LoginMember member, - @RequestPart StudyCreateCommand request, - @RequestPart MultipartFile studyMainImage + @Valid StudyCreateCommand request ) { - Long createdStudyId = studyCreateUseCase.create(request, member.getMember(), studyMainImage); + Long createdStudyId = studyCreateUseCase.create(request, member.getMember()); StudyDetailResponse response = studyQueryUseCase.getStudyDetailById(createdStudyId); return new ResponseEntity<>( diff --git a/src/main/java/com/stumeet/server/study/application/port/in/StudyCreateUseCase.java b/src/main/java/com/stumeet/server/study/application/port/in/StudyCreateUseCase.java index 52f9b054..6cbc068e 100644 --- a/src/main/java/com/stumeet/server/study/application/port/in/StudyCreateUseCase.java +++ b/src/main/java/com/stumeet/server/study/application/port/in/StudyCreateUseCase.java @@ -1,11 +1,9 @@ package com.stumeet.server.study.application.port.in; -import org.springframework.web.multipart.MultipartFile; - 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, MultipartFile mainImage); + Long create(StudyCreateCommand command, Member member); } diff --git a/src/main/java/com/stumeet/server/study/application/port/in/command/StudyCreateCommand.java b/src/main/java/com/stumeet/server/study/application/port/in/command/StudyCreateCommand.java index afe6ea03..1fb998d9 100644 --- a/src/main/java/com/stumeet/server/study/application/port/in/command/StudyCreateCommand.java +++ b/src/main/java/com/stumeet/server/study/application/port/in/command/StudyCreateCommand.java @@ -1,31 +1,39 @@ package com.stumeet.server.study.application.port.in.command; -import java.time.LocalDateTime; +import java.time.LocalDate; import java.time.LocalTime; import java.util.List; +import org.springframework.web.multipart.MultipartFile; + +import com.stumeet.server.common.annotation.validator.NullOrImageFile; +import com.stumeet.server.common.annotation.validator.NullOrNotBlank; import com.stumeet.server.study.domain.RepetitionType; import jakarta.validation.constraints.NotBlank; import jakarta.validation.constraints.NotNull; public record StudyCreateCommand( - @NotNull + + @NullOrImageFile(message = "이미지 파일을 첨부해주세요") + MultipartFile image, + @NotNull(message = "스터디 분야 ID를 입력해주세요.") Long studyFieldId, - @NotBlank + @NotBlank(message = "이름을 입력해주세요.") String name, - @NotBlank + @NotBlank(message = "소개글을 입력해주세요.") String intro, - @NotBlank + @NotBlank(message = "지역을 입력해주세요.") String region, + @NullOrNotBlank(message = "규칙은 공백일 수 없습니다.") String rule, - @NotNull - LocalDateTime startDate, - @NotNull - LocalDateTime endDate, - @NotNull + @NotNull(message = "시작일을 입력해주세요.") + LocalDate startDate, + @NotNull(message = "종료일을 입력해주세요.") + LocalDate endDate, + @NotNull(message = "정기모임 시간을 입력해주세요.") LocalTime meetingTime, - @NotNull + @NotNull(message = "정기모임 반복 유형을 입력해주세요.") RepetitionType meetingRepetitionType, List meetingRepetitionDates, List studyTags diff --git a/src/main/java/com/stumeet/server/study/domain/StudyPeriod.java b/src/main/java/com/stumeet/server/study/domain/StudyPeriod.java index 82e87774..aab28efa 100644 --- a/src/main/java/com/stumeet/server/study/domain/StudyPeriod.java +++ b/src/main/java/com/stumeet/server/study/domain/StudyPeriod.java @@ -1,6 +1,6 @@ package com.stumeet.server.study.domain; -import java.time.LocalDateTime; +import java.time.LocalDate; import lombok.AccessLevel; import lombok.AllArgsConstructor; @@ -10,11 +10,11 @@ @Getter public class StudyPeriod { - private LocalDateTime startDate; + private LocalDate startDate; - private LocalDateTime endDate; + private LocalDate endDate; - public static StudyPeriod of(LocalDateTime startDate, LocalDateTime endDate) { + public static StudyPeriod of(LocalDate startDate, LocalDate endDate) { return new StudyPeriod(startDate, endDate); } } From 36bcf1e0e78952027094a11645142d40df524939 Mon Sep 17 00:00:00 2001 From: Lee ChanMi Date: Tue, 2 Apr 2024 11:44:12 +0900 Subject: [PATCH 10/35] =?UTF-8?q?:sparkles:=20[STMT-62]=20=EC=9D=B4?= =?UTF-8?q?=EB=AF=B8=EC=A7=80=20=ED=95=84=EB=93=9C=EB=A5=BC=20nullable?= =?UTF-8?q?=EB=A1=9C=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../study/application/service/StudyCreateService.java | 7 ++++--- src/main/resources/db/migration/V1.4__add_study_table.sql | 2 +- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/src/main/java/com/stumeet/server/study/application/service/StudyCreateService.java b/src/main/java/com/stumeet/server/study/application/service/StudyCreateService.java index d751dd19..b121b361 100644 --- a/src/main/java/com/stumeet/server/study/application/service/StudyCreateService.java +++ b/src/main/java/com/stumeet/server/study/application/service/StudyCreateService.java @@ -1,7 +1,6 @@ package com.stumeet.server.study.application.service; import org.springframework.transaction.annotation.Transactional; -import org.springframework.web.multipart.MultipartFile; import com.stumeet.server.common.annotation.UseCase; import com.stumeet.server.file.application.port.in.FileUploadUseCase; @@ -40,11 +39,13 @@ public class StudyCreateService implements StudyCreateUseCase { @Override @Transactional - public Long create(StudyCreateCommand command, Member member, MultipartFile mainImage) { + public Long create(StudyCreateCommand command, Member member) { studyFieldQueryPort.checkById(command.studyFieldId()); StudyDomain studyDomainCreated = createStudyDomain(studyDomainUseCaseMapper.toDomain(command)); - String mainImageUrl = fileUploadUseCase.uploadStudyMainImage(mainImage).url(); + String mainImageUrl = command.image() != null + ? fileUploadUseCase.uploadStudyMainImage(command.image()).url() + : null; Study study = Study.builder() .studyDomain(studyDomainCreated) diff --git a/src/main/resources/db/migration/V1.4__add_study_table.sql b/src/main/resources/db/migration/V1.4__add_study_table.sql index de99213e..80ed7637 100644 --- a/src/main/resources/db/migration/V1.4__add_study_table.sql +++ b/src/main/resources/db/migration/V1.4__add_study_table.sql @@ -26,7 +26,7 @@ CREATE TABLE `study` `region` VARCHAR(50) NOT NULL COMMENT '활동 지역', `intro` VARCHAR(200) NOT NULL COMMENT '소개', `rule` VARCHAR(200) NULL COMMENT '규칙', - `image` VARCHAR(500) NOT NULL COMMENT '스터디 이미지의 URL', + `image` VARCHAR(500) NULL COMMENT '스터디 이미지의 URL', `headcount` TINYINT(100) NOT NULL DEFAULT 1 COMMENT '인원 수', `start_date` DATETIME NOT NULL COMMENT '시작일', `end_date` DATETIME NOT NULL COMMENT '종료일', From 8b14b5c00c67ec2f77e84b3f465a4c7c6a7681b8 Mon Sep 17 00:00:00 2001 From: Lee ChanMi Date: Tue, 2 Apr 2024 23:44:26 +0900 Subject: [PATCH 11/35] =?UTF-8?q?:adhesive=5Fbandage:=20[STMT-62]=20?= =?UTF-8?q?=EC=8B=9C=EC=9E=91=EC=9D=BC,=20=EC=A2=85=EB=A3=8C=EC=9D=BC=20?= =?UTF-8?q?=EB=8D=B0=EC=9D=B4=ED=84=B0=ED=98=95=EC=9D=84=20LocalDateTime?= =?UTF-8?q?=EC=97=90=EC=84=9C=20LocalDate=EB=A1=9C=20=EB=B3=80=EA=B2=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../adapter/out/persistance/entity/StudyJpaEntity.java | 5 +++-- .../application/port/in/response/StudyDetailResponse.java | 6 +++--- src/main/java/com/stumeet/server/study/domain/Study.java | 6 +++--- 3 files changed, 9 insertions(+), 8 deletions(-) diff --git a/src/main/java/com/stumeet/server/study/adapter/out/persistance/entity/StudyJpaEntity.java b/src/main/java/com/stumeet/server/study/adapter/out/persistance/entity/StudyJpaEntity.java index 71b81b3a..f137b567 100644 --- a/src/main/java/com/stumeet/server/study/adapter/out/persistance/entity/StudyJpaEntity.java +++ b/src/main/java/com/stumeet/server/study/adapter/out/persistance/entity/StudyJpaEntity.java @@ -1,5 +1,6 @@ package com.stumeet.server.study.adapter.out.persistance.entity; +import java.time.LocalDate; import java.time.LocalDateTime; import java.time.LocalTime; @@ -67,11 +68,11 @@ public class StudyJpaEntity extends BaseTimeEntity { @Column(name = "start_date", nullable = false) @Comment("시작일") - private LocalDateTime startDate; + private LocalDate startDate; @Column(name = "end_date", nullable = false) @Comment("종료일") - private LocalDateTime endDate; + private LocalDate endDate; @Column(name = "meeting_time", nullable = false) @Comment("정기모임 시간") diff --git a/src/main/java/com/stumeet/server/study/application/port/in/response/StudyDetailResponse.java b/src/main/java/com/stumeet/server/study/application/port/in/response/StudyDetailResponse.java index a1c1609b..4972fe28 100644 --- a/src/main/java/com/stumeet/server/study/application/port/in/response/StudyDetailResponse.java +++ b/src/main/java/com/stumeet/server/study/application/port/in/response/StudyDetailResponse.java @@ -1,6 +1,6 @@ package com.stumeet.server.study.application.port.in.response; -import java.time.LocalDateTime; +import java.time.LocalDate; import java.time.LocalTime; import java.util.List; @@ -17,8 +17,8 @@ public record StudyDetailResponse( String rule, String image, int headcount, - LocalDateTime startDate, - LocalDateTime endDate, + LocalDate startDate, + LocalDate endDate, LocalTime meetingTime, String meetingRepetitionType, List meetingRepetitionDates, diff --git a/src/main/java/com/stumeet/server/study/domain/Study.java b/src/main/java/com/stumeet/server/study/domain/Study.java index 2a189e07..ecb581f3 100644 --- a/src/main/java/com/stumeet/server/study/domain/Study.java +++ b/src/main/java/com/stumeet/server/study/domain/Study.java @@ -1,6 +1,6 @@ package com.stumeet.server.study.domain; -import java.time.LocalDateTime; +import java.time.LocalDate; import java.time.LocalTime; import java.util.List; @@ -50,11 +50,11 @@ public int getHeadcountNumber() { return headcount.getNumber(); } - public LocalDateTime getStartDate() { + public LocalDate getStartDate() { return period.getStartDate(); } - public LocalDateTime getEndDate() { + public LocalDate getEndDate() { return period.getEndDate(); } From e79ce74ca40cd249c7704dfa0572d822f0c02fb9 Mon Sep 17 00:00:00 2001 From: Lee ChanMi Date: Tue, 2 Apr 2024 23:45:19 +0900 Subject: [PATCH 12/35] =?UTF-8?q?:white=5Fcheck=5Fmark:=20[STMT-62]=20?= =?UTF-8?q?=ED=85=8C=EC=8A=A4=ED=8A=B8=20=EC=BD=94=EB=93=9C=EC=97=90?= =?UTF-8?q?=EC=84=9C=20@transactional=20=EC=A0=9C=EA=B1=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../stumeet/server/study/adapter/in/web/StudyQueryApiTest.java | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/test/java/com/stumeet/server/study/adapter/in/web/StudyQueryApiTest.java b/src/test/java/com/stumeet/server/study/adapter/in/web/StudyQueryApiTest.java index b29d3772..39bc4e64 100644 --- a/src/test/java/com/stumeet/server/study/adapter/in/web/StudyQueryApiTest.java +++ b/src/test/java/com/stumeet/server/study/adapter/in/web/StudyQueryApiTest.java @@ -11,7 +11,6 @@ import org.junit.jupiter.api.DisplayName; import org.junit.jupiter.api.Nested; import org.junit.jupiter.api.Test; -import org.springframework.transaction.annotation.Transactional; import com.stumeet.server.common.auth.model.AuthenticationHeader; import com.stumeet.server.helper.WithMockMember; @@ -26,7 +25,6 @@ class StudyQueryApiTest extends ApiTest { class GetStudyDetail { @Test - @Transactional @WithMockMember @DisplayName("[성공] 스터디 상세 정보 조회를 성공한다.") void successTest() throws Exception { From bd22f7d0aa91bd9433789bff3e2f398981ba25a6 Mon Sep 17 00:00:00 2001 From: Lee ChanMi Date: Tue, 2 Apr 2024 23:46:50 +0900 Subject: [PATCH 13/35] =?UTF-8?q?:white=5Fcheck=5Fmark:=20[STMT-62]=20?= =?UTF-8?q?=EC=8A=A4=ED=84=B0=EB=94=94=20=EC=83=9D=EC=84=B1=20api=20?= =?UTF-8?q?=EC=84=B1=EA=B3=B5=20=ED=85=8C=EC=8A=A4=ED=8A=B8=20=EC=B6=94?= =?UTF-8?q?=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../com/stumeet/server/stub/StudyStub.java | 27 ++++ .../adapter/in/web/StudyCreateApiTest.java | 118 ++++++++++++++++++ 2 files changed, 145 insertions(+) create mode 100644 src/test/java/com/stumeet/server/study/adapter/in/web/StudyCreateApiTest.java diff --git a/src/test/java/com/stumeet/server/stub/StudyStub.java b/src/test/java/com/stumeet/server/stub/StudyStub.java index 825bc027..7c2a5023 100644 --- a/src/test/java/com/stumeet/server/stub/StudyStub.java +++ b/src/test/java/com/stumeet/server/stub/StudyStub.java @@ -1,5 +1,14 @@ package com.stumeet.server.stub; +import java.time.LocalDate; +import java.time.LocalTime; +import java.util.Arrays; + +import org.springframework.mock.web.MockMultipartFile; + +import com.stumeet.server.study.application.port.in.command.StudyCreateCommand; +import com.stumeet.server.study.domain.RepetitionType; + public class StudyStub { private StudyStub() { @@ -12,4 +21,22 @@ public static Long getStudyId() { public static Long getInvalidStudyId() { return 0L; } + + public static StudyCreateCommand getStudyCreateCommand() { + MockMultipartFile image = new MockMultipartFile("image", "test.jpg", "image/jpeg", "test".getBytes()); + return new StudyCreateCommand( + image, + 1L, + "영어 회화 클럽", + "매주 영어로 대화하며 언어 실력을 향상시키는 스터디 그룹입니다.", + "부산", + "주 1회 대면 미팅 및 온라인 토론", + LocalDate.parse("2024-05-15"), + LocalDate.parse("2024-12-15"), + LocalTime.parse("18:30:00"), + RepetitionType.valueOf("WEEKLY"), + Arrays.asList("월", "금"), + Arrays.asList("영어", "회화", "언어 교환") + ); + } } diff --git a/src/test/java/com/stumeet/server/study/adapter/in/web/StudyCreateApiTest.java b/src/test/java/com/stumeet/server/study/adapter/in/web/StudyCreateApiTest.java new file mode 100644 index 00000000..6ee84b35 --- /dev/null +++ b/src/test/java/com/stumeet/server/study/adapter/in/web/StudyCreateApiTest.java @@ -0,0 +1,118 @@ +package com.stumeet.server.study.adapter.in.web; + +import static org.springframework.restdocs.headers.HeaderDocumentation.*; +import static org.springframework.restdocs.mockmvc.MockMvcRestDocumentation.*; +import static org.springframework.restdocs.mockmvc.RestDocumentationRequestBuilders.*; +import static org.springframework.restdocs.operation.preprocess.Preprocessors.*; +import static org.springframework.restdocs.payload.PayloadDocumentation.*; +import static org.springframework.restdocs.request.RequestDocumentation.*; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.*; +import static org.springframework.restdocs.snippet.Attributes.key; + +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Nested; +import org.junit.jupiter.api.Test; +import org.springframework.http.MediaType; +import org.springframework.mock.web.MockMultipartFile; +import org.springframework.test.web.servlet.request.RequestPostProcessor; + +import com.stumeet.server.common.auth.model.AuthenticationHeader; +import com.stumeet.server.helper.WithMockMember; +import com.stumeet.server.stub.StudyStub; +import com.stumeet.server.stub.TokenStub; +import com.stumeet.server.study.application.port.in.command.StudyCreateCommand; +import com.stumeet.server.template.ApiTest; + +class StudyCreateApiTest extends ApiTest { + + @Nested + @DisplayName("스터디 생성하기") + class CreateStudy { + + private final String path = "/api/v1/studies"; + + @Test + @WithMockMember + @DisplayName("[성공] 스터디 생성에 성공한다.") + void successTest() throws Exception { + StudyCreateCommand request = StudyStub.getStudyCreateCommand(); + + RequestPostProcessor postMethod = http -> { + http.setMethod("POST"); + return http; + }; + mockMvc.perform(multipart(path) + .file((MockMultipartFile)request.image()) + .with(postMethod) + .header(AuthenticationHeader.ACCESS_TOKEN.getName(), TokenStub.getMockAccessToken()) + .queryParam("studyFieldId", String.valueOf(request.studyFieldId())) + .queryParam("name", request.name()) + .queryParam("intro", request.intro()) + .queryParam("region", request.region()) + .queryParam("rule", request.rule()) + .queryParam("startDate", String.valueOf(request.startDate())) + .queryParam("endDate", String.valueOf(request.endDate())) + .queryParam("meetingTime", String.valueOf(request.meetingTime())) + .queryParam("meetingRepetitionType", request.meetingRepetitionType().name()) + .queryParam("meetingRepetitionDates", String.valueOf(request.meetingRepetitionDates())) + .queryParam("studyTags", String.valueOf(request.studyTags())) + .contentType(MediaType.MULTIPART_FORM_DATA) + .accept(MediaType.APPLICATION_JSON)) + .andExpect(status().isCreated()) + .andDo(document("create-study/success", + preprocessRequest(prettyPrint()), + preprocessResponse(prettyPrint()), + requestHeaders( + headerWithName(AuthenticationHeader.ACCESS_TOKEN.getName()) + .description("서버로부터 전달받은 액세스 토큰") + ), + requestParts( + partWithName("image").description("스터디 메인 이미지 파일").optional() + ), + queryParameters( + parameterWithName("studyFieldId").description("스터디 분야 ID") + .attributes(key("constraint").value("NotNull, 스터디 분야 ID를 입력해주세요.")), + parameterWithName("name").description("스터디 이름") + .attributes(key("constraint").value("NotBlank, 이름을 입력해주세요.")), + parameterWithName("intro").description("소개") + .attributes(key("constraint").value("NotBlank, 소개글을 입력해주세요.")), + parameterWithName("region").description("활동 지역") + .attributes(key("constraint").value("NotBlank, 지역을 입력해주세요.")), + parameterWithName("rule").description("규칙").optional() + .attributes(key("constraint").value("NullOrNotBlank, 규칙은 공백일 수 없습니다.")), + parameterWithName("startDate").description("시작일") + .attributes(key("constraint").value("NotNull, 시작일을 입력해주세요.")), + parameterWithName("endDate").description("종료일") + .attributes(key("constraint").value("NotNull, 종료일을 입력해주세요.")), + parameterWithName("meetingTime").description("정기모임 시간") + .attributes(key("constraint").value("NotNull, 정기모임 시간을 입력해주세요.")), + parameterWithName("meetingRepetitionType").description("정기모임 반복 유형") + .attributes(key("constraint").value("NotNull, 정기모임 반복 유형을 입력해주세요.")), + parameterWithName("meetingRepetitionDates").description("정기모임 반복 일자").optional(), + parameterWithName("studyTags").description("스터디 태그").optional() + ), + responseFields( + fieldWithPath("code").description("응답 상태"), + fieldWithPath("message").description("응답 메시지"), + fieldWithPath("data.id").description("스터디 ID"), + fieldWithPath("data.field").description("분야"), + fieldWithPath("data.name").description("스터디 이름"), + fieldWithPath("data.tags").description("태그 리스트"), + fieldWithPath("data.intro").description("소개"), + fieldWithPath("data.region").description("활동 지역"), + fieldWithPath("data.rule").description("규칙"), + fieldWithPath("data.image").description("이미지 URL"), + fieldWithPath("data.headcount").description("참여 인원 수"), + fieldWithPath("data.startDate").description("시작일"), + fieldWithPath("data.endDate").description("종료일"), + fieldWithPath("data.meetingTime").description("정기모임 시간"), + fieldWithPath("data.meetingRepetitionType") + .description("정기모임 반복 유형 / `매일`, `매주`, `매달`"), + fieldWithPath("data.meetingRepetitionDates") + .description("정기모임 반복일 / 매주: 요일, 매달: 날짜"), + fieldWithPath("data.isFinished").description("종료 여부"), + fieldWithPath("data.isDeleted").description("삭제 여부") + ))); + } + } +} \ No newline at end of file From 08f7baee808b57460dbb005e0bf1b96bd32cc139 Mon Sep 17 00:00:00 2001 From: Lee ChanMi Date: Tue, 2 Apr 2024 23:47:17 +0900 Subject: [PATCH 14/35] =?UTF-8?q?:white=5Fcheck=5Fmark:=20[STMT-62]=20?= =?UTF-8?q?=EC=8A=A4=ED=84=B0=EB=94=94=20=EC=83=9D=EC=84=B1=20api=20?= =?UTF-8?q?=EC=9D=B4=EB=AF=B8=EC=A7=80=20null=EC=9D=BC=20=EA=B2=BD?= =?UTF-8?q?=EC=9A=B0=EC=97=90=EB=8F=84=20=EC=84=B1=EA=B3=B5=20=ED=85=8C?= =?UTF-8?q?=EC=8A=A4=ED=8A=B8=20=EC=BC=80=EC=9D=B4=EC=8A=A4=20=EC=B6=94?= =?UTF-8?q?=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../adapter/in/web/StudyCreateApiTest.java | 31 ++++++++++++++++++- 1 file changed, 30 insertions(+), 1 deletion(-) diff --git a/src/test/java/com/stumeet/server/study/adapter/in/web/StudyCreateApiTest.java b/src/test/java/com/stumeet/server/study/adapter/in/web/StudyCreateApiTest.java index 6ee84b35..4e6fdf9e 100644 --- a/src/test/java/com/stumeet/server/study/adapter/in/web/StudyCreateApiTest.java +++ b/src/test/java/com/stumeet/server/study/adapter/in/web/StudyCreateApiTest.java @@ -42,7 +42,7 @@ void successTest() throws Exception { return http; }; mockMvc.perform(multipart(path) - .file((MockMultipartFile)request.image()) + .file((MockMultipartFile) request.image()) .with(postMethod) .header(AuthenticationHeader.ACCESS_TOKEN.getName(), TokenStub.getMockAccessToken()) .queryParam("studyFieldId", String.valueOf(request.studyFieldId())) @@ -114,5 +114,34 @@ void successTest() throws Exception { fieldWithPath("data.isDeleted").description("삭제 여부") ))); } + + @Test + @WithMockMember + @DisplayName("[성공] 이미지 파일이 없어도 요청에 성공한다.") + void successWithoutImageFile() throws Exception { + StudyCreateCommand request = StudyStub.getStudyCreateCommand(); + + RequestPostProcessor postMethod = http -> { + http.setMethod("POST"); + return http; + }; + mockMvc.perform(multipart(path) + .with(postMethod) + .header(AuthenticationHeader.ACCESS_TOKEN.getName(), TokenStub.getMockAccessToken()) + .queryParam("studyFieldId", String.valueOf(request.studyFieldId())) + .queryParam("name", request.name()) + .queryParam("intro", request.intro()) + .queryParam("region", request.region()) + .queryParam("rule", request.rule()) + .queryParam("startDate", String.valueOf(request.startDate())) + .queryParam("endDate", String.valueOf(request.endDate())) + .queryParam("meetingTime", String.valueOf(request.meetingTime())) + .queryParam("meetingRepetitionType", request.meetingRepetitionType().name()) + .queryParam("meetingRepetitionDates", String.valueOf(request.meetingRepetitionDates())) + .queryParam("studyTags", String.valueOf(request.studyTags())) + .contentType(MediaType.MULTIPART_FORM_DATA) + .accept(MediaType.APPLICATION_JSON)) + .andExpect(status().isCreated()); + } } } \ No newline at end of file From aa7022025d550ce630f0134252933b684475d823 Mon Sep 17 00:00:00 2001 From: Lee ChanMi Date: Wed, 3 Apr 2024 15:25:11 +0900 Subject: [PATCH 15/35] =?UTF-8?q?:goal=5Fnet:=20[STMT-146]=20=EA=B3=B5?= =?UTF-8?q?=ED=86=B5=20=EC=BB=A4=EC=8A=A4=ED=85=80=20=EC=98=88=EC=99=B8=20?= =?UTF-8?q?InvalidFileException=20=EC=9D=B4=EB=A6=84=20=EB=B3=80=EA=B2=BD?= =?UTF-8?q?=20->=20InvalidResourceException=20=EB=B0=8F=20=EC=9D=B4?= =?UTF-8?q?=EB=A5=BC=20=EC=83=81=EC=86=8D=ED=95=9C=20InvalidFileException?= =?UTF-8?q?=20=EC=83=9D=EC=84=B1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- ...ileException.java => InvalidResourceException.java} | 4 ++-- .../com/stumeet/server/common/util/FileValidator.java | 2 +- .../file/domain/exception/InvalidFileException.java | 10 ++++++++++ 3 files changed, 13 insertions(+), 3 deletions(-) rename src/main/java/com/stumeet/server/common/exception/model/{InvalidFileException.java => InvalidResourceException.java} (51%) create mode 100644 src/main/java/com/stumeet/server/file/domain/exception/InvalidFileException.java diff --git a/src/main/java/com/stumeet/server/common/exception/model/InvalidFileException.java b/src/main/java/com/stumeet/server/common/exception/model/InvalidResourceException.java similarity index 51% rename from src/main/java/com/stumeet/server/common/exception/model/InvalidFileException.java rename to src/main/java/com/stumeet/server/common/exception/model/InvalidResourceException.java index be4b4610..22c353c7 100644 --- a/src/main/java/com/stumeet/server/common/exception/model/InvalidFileException.java +++ b/src/main/java/com/stumeet/server/common/exception/model/InvalidResourceException.java @@ -2,8 +2,8 @@ import com.stumeet.server.common.response.ErrorCode; -public class InvalidFileException extends BusinessException { - public InvalidFileException(ErrorCode errorCode) { +public class InvalidResourceException extends BusinessException { + public InvalidResourceException(ErrorCode errorCode) { super(errorCode); } } diff --git a/src/main/java/com/stumeet/server/common/util/FileValidator.java b/src/main/java/com/stumeet/server/common/util/FileValidator.java index 9cd9602b..dac01eed 100644 --- a/src/main/java/com/stumeet/server/common/util/FileValidator.java +++ b/src/main/java/com/stumeet/server/common/util/FileValidator.java @@ -2,9 +2,9 @@ import org.springframework.web.multipart.MultipartFile; -import com.stumeet.server.common.exception.model.InvalidFileException; import com.stumeet.server.common.response.ErrorCode; import com.stumeet.server.file.domain.ImageContentType; +import com.stumeet.server.file.domain.exception.InvalidFileException; import lombok.AccessLevel; import lombok.NoArgsConstructor; diff --git a/src/main/java/com/stumeet/server/file/domain/exception/InvalidFileException.java b/src/main/java/com/stumeet/server/file/domain/exception/InvalidFileException.java new file mode 100644 index 00000000..5459fd71 --- /dev/null +++ b/src/main/java/com/stumeet/server/file/domain/exception/InvalidFileException.java @@ -0,0 +1,10 @@ +package com.stumeet.server.file.domain.exception; + +import com.stumeet.server.common.exception.model.InvalidResourceException; +import com.stumeet.server.common.response.ErrorCode; + +public class InvalidFileException extends InvalidResourceException { + public InvalidFileException(ErrorCode errorCode) { + super(errorCode); + } +} From 2819bc6c71ed476f3d32069a29e05ad45f3c048a Mon Sep 17 00:00:00 2001 From: Lee ChanMi Date: Wed, 3 Apr 2024 15:26:48 +0900 Subject: [PATCH 16/35] =?UTF-8?q?:recycle:=20[STMT-62]=20study=EB=A5=BC=20?= =?UTF-8?q?=EC=83=9D=EC=84=B1=ED=95=98=EB=8A=94=20=EB=A1=9C=EC=A7=81?= =?UTF-8?q?=EC=9D=84=20study=20=EB=82=B4=EB=B6=80=EB=A1=9C=20=EC=9D=B4?= =?UTF-8?q?=EC=A0=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../MeetingRepetitionPersistenceMapper.java | 7 ++-- .../mapper/MeetingScheduleUseCaseMapper.java | 18 ---------- .../service/StudyCreateService.java | 20 +---------- .../stumeet/server/study/domain/Study.java | 36 +++++++++++++++++++ .../server/study/domain/StudyHeadCount.java | 7 +--- .../server/study/domain/StudyPeriod.java | 6 ++-- 6 files changed, 44 insertions(+), 50 deletions(-) delete mode 100644 src/main/java/com/stumeet/server/study/application/port/in/mapper/MeetingScheduleUseCaseMapper.java diff --git a/src/main/java/com/stumeet/server/study/adapter/out/persistance/mapper/MeetingRepetitionPersistenceMapper.java b/src/main/java/com/stumeet/server/study/adapter/out/persistance/mapper/MeetingRepetitionPersistenceMapper.java index e1198548..7c0d4068 100644 --- a/src/main/java/com/stumeet/server/study/adapter/out/persistance/mapper/MeetingRepetitionPersistenceMapper.java +++ b/src/main/java/com/stumeet/server/study/adapter/out/persistance/mapper/MeetingRepetitionPersistenceMapper.java @@ -15,9 +15,10 @@ public class MeetingRepetitionPersistenceMapper { public StudyMeetingSchedule.Repetition toDomain(String meetingRepetition) { List repetitionElements = List.of(meetingRepetition.split(REPEAT_DELIMITER)); - return StudyMeetingSchedule.Repetition.of( - RepetitionType.valueOf(repetitionElements.getFirst()), - repetitionElements.subList(1, repetitionElements.size())); + return StudyMeetingSchedule.Repetition.builder() + .type(RepetitionType.valueOf(repetitionElements.getFirst())) + .dates(repetitionElements.subList(1, repetitionElements.size())) + .build(); } public String toColumn(StudyMeetingSchedule.Repetition repetition) { diff --git a/src/main/java/com/stumeet/server/study/application/port/in/mapper/MeetingScheduleUseCaseMapper.java b/src/main/java/com/stumeet/server/study/application/port/in/mapper/MeetingScheduleUseCaseMapper.java deleted file mode 100644 index f0fddac4..00000000 --- a/src/main/java/com/stumeet/server/study/application/port/in/mapper/MeetingScheduleUseCaseMapper.java +++ /dev/null @@ -1,18 +0,0 @@ -package com.stumeet.server.study.application.port.in.mapper; - -import org.springframework.stereotype.Component; - -import com.stumeet.server.study.application.port.in.command.StudyCreateCommand; -import com.stumeet.server.study.domain.StudyMeetingSchedule; - -@Component -public class MeetingScheduleUseCaseMapper { - - public StudyMeetingSchedule toDomain(StudyCreateCommand command) { - return StudyMeetingSchedule.of( - command.meetingTime(), - StudyMeetingSchedule.Repetition.of( - command.meetingRepetitionType(), - command.meetingRepetitionDates())); - } -} \ No newline at end of file diff --git a/src/main/java/com/stumeet/server/study/application/service/StudyCreateService.java b/src/main/java/com/stumeet/server/study/application/service/StudyCreateService.java index b121b361..da4d7f38 100644 --- a/src/main/java/com/stumeet/server/study/application/service/StudyCreateService.java +++ b/src/main/java/com/stumeet/server/study/application/service/StudyCreateService.java @@ -7,7 +7,6 @@ import com.stumeet.server.member.domain.Member; import com.stumeet.server.study.application.port.in.StudyCreateUseCase; import com.stumeet.server.study.application.port.in.command.StudyCreateCommand; -import com.stumeet.server.study.application.port.in.mapper.MeetingScheduleUseCaseMapper; import com.stumeet.server.study.application.port.in.mapper.StudyDomainUseCaseMapper; import com.stumeet.server.study.application.port.out.StudyCommandPort; import com.stumeet.server.study.application.port.out.StudyDomainCommandPort; @@ -15,8 +14,6 @@ import com.stumeet.server.study.application.port.out.StudyTagCommandPort; import com.stumeet.server.study.domain.Study; import com.stumeet.server.study.domain.StudyDomain; -import com.stumeet.server.study.domain.StudyHeadCount; -import com.stumeet.server.study.domain.StudyPeriod; import com.stumeet.server.studymember.application.port.in.StudyMemberJoinUseCase; import com.stumeet.server.studymember.application.port.in.command.StudyMemberJoinCommand; @@ -35,7 +32,6 @@ public class StudyCreateService implements StudyCreateUseCase { private final StudyTagCommandPort studyTagCommandPort; private final StudyDomainUseCaseMapper studyDomainUseCaseMapper; - private final MeetingScheduleUseCaseMapper meetingScheduleUseCaseMapper; @Override @Transactional @@ -46,21 +42,7 @@ public Long create(StudyCreateCommand command, Member member) { String mainImageUrl = command.image() != null ? fileUploadUseCase.uploadStudyMainImage(command.image()).url() : null; - - Study study = Study.builder() - .studyDomain(studyDomainCreated) - .name(command.name()) - .intro(command.intro()) - .rule(command.rule()) - .region(command.region()) - .period(StudyPeriod.of(command.startDate(), command.endDate())) - .meetingSchedule(meetingScheduleUseCaseMapper.toDomain(command)) - .headcount(StudyHeadCount.from(1)) - .image(mainImageUrl) - .isFinished(false) - .isDeleted(false) - .build(); - + Study study = Study.create(command, studyDomainCreated, mainImageUrl); Study studyCreated = studyCommandPort.save(study); StudyMemberJoinCommand studyMemberJoinCommand = StudyMemberJoinCommand.builder() diff --git a/src/main/java/com/stumeet/server/study/domain/Study.java b/src/main/java/com/stumeet/server/study/domain/Study.java index ecb581f3..19f410d3 100644 --- a/src/main/java/com/stumeet/server/study/domain/Study.java +++ b/src/main/java/com/stumeet/server/study/domain/Study.java @@ -4,6 +4,8 @@ import java.time.LocalTime; import java.util.List; +import com.stumeet.server.study.application.port.in.command.StudyCreateCommand; + import lombok.AccessLevel; import lombok.AllArgsConstructor; import lombok.Builder; @@ -14,6 +16,8 @@ @Getter public class Study { + private static final int INITIAL_STUDY_HEAD_COUNT = 1; + private Long id; private String name; @@ -38,6 +42,38 @@ public class Study { private boolean isDeleted; + public static Study create(StudyCreateCommand command, StudyDomain studyDomain, String imageUrl) { + StudyMeetingSchedule meetingSchedule = + StudyMeetingSchedule.builder() + .time(command.meetingTime()) + .repetition(StudyMeetingSchedule.Repetition.builder() + .type(command.meetingRepetitionType()) + .dates(command.meetingRepetitionDates()) + .build()) + .build(); + + StudyPeriod studyPeriod = StudyPeriod.builder() + .startDate(command.startDate()) + .endDate(command.endDate()) + .build(); + + StudyHeadCount studyHeadCount = new StudyHeadCount(INITIAL_STUDY_HEAD_COUNT); + + return Study.builder() + .studyDomain(studyDomain) + .name(command.name()) + .intro(command.intro()) + .rule(command.rule()) + .region(command.region()) + .period(studyPeriod) + .meetingSchedule(meetingSchedule) + .headcount(studyHeadCount) + .image(imageUrl) + .isFinished(false) + .isDeleted(false) + .build(); + } + public String getStudyFieldName() { return studyDomain.getStudyFieldName(); } diff --git a/src/main/java/com/stumeet/server/study/domain/StudyHeadCount.java b/src/main/java/com/stumeet/server/study/domain/StudyHeadCount.java index b17d4e07..d6212697 100644 --- a/src/main/java/com/stumeet/server/study/domain/StudyHeadCount.java +++ b/src/main/java/com/stumeet/server/study/domain/StudyHeadCount.java @@ -1,17 +1,12 @@ package com.stumeet.server.study.domain; -import lombok.AccessLevel; import lombok.AllArgsConstructor; import lombok.Getter; -@AllArgsConstructor(access = AccessLevel.PRIVATE) +@AllArgsConstructor @Getter public class StudyHeadCount { private int number; - - public static StudyHeadCount from(int number) { - return new StudyHeadCount(number); - } } diff --git a/src/main/java/com/stumeet/server/study/domain/StudyPeriod.java b/src/main/java/com/stumeet/server/study/domain/StudyPeriod.java index aab28efa..b7227e33 100644 --- a/src/main/java/com/stumeet/server/study/domain/StudyPeriod.java +++ b/src/main/java/com/stumeet/server/study/domain/StudyPeriod.java @@ -4,8 +4,10 @@ import lombok.AccessLevel; import lombok.AllArgsConstructor; +import lombok.Builder; import lombok.Getter; +@Builder @AllArgsConstructor(access = AccessLevel.PRIVATE) @Getter public class StudyPeriod { @@ -13,8 +15,4 @@ public class StudyPeriod { private LocalDate startDate; private LocalDate endDate; - - public static StudyPeriod of(LocalDate startDate, LocalDate endDate) { - return new StudyPeriod(startDate, endDate); - } } From 73d0d004124ac9de69b2b536341fc2700bebc789 Mon Sep 17 00:00:00 2001 From: Lee ChanMi Date: Wed, 3 Apr 2024 15:27:12 +0900 Subject: [PATCH 17/35] =?UTF-8?q?:sparkles:=20[STMT-62]=20=EC=9D=BC?= =?UTF-8?q?=EC=A0=95=20=EB=B0=98=EB=B3=B5=20=ED=83=80=EC=9E=85=EC=9D=84=20?= =?UTF-8?q?=EA=B2=80=EC=A6=9D=ED=95=98=EB=8A=94=20=EB=A1=9C=EC=A7=81=20?= =?UTF-8?q?=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../study/domain/StudyMeetingSchedule.java | 20 +++++++++++++++---- .../InvalidRepetitionDatesException.java | 10 ++++++++++ 2 files changed, 26 insertions(+), 4 deletions(-) create mode 100644 src/main/java/com/stumeet/server/study/domain/exception/InvalidRepetitionDatesException.java diff --git a/src/main/java/com/stumeet/server/study/domain/StudyMeetingSchedule.java b/src/main/java/com/stumeet/server/study/domain/StudyMeetingSchedule.java index ad6142ca..4a843834 100644 --- a/src/main/java/com/stumeet/server/study/domain/StudyMeetingSchedule.java +++ b/src/main/java/com/stumeet/server/study/domain/StudyMeetingSchedule.java @@ -3,10 +3,14 @@ import java.time.LocalTime; import java.util.List; +import com.stumeet.server.study.domain.exception.InvalidRepetitionDatesException; + import lombok.AccessLevel; import lombok.AllArgsConstructor; +import lombok.Builder; import lombok.Getter; +@Builder @AllArgsConstructor(access = AccessLevel.PRIVATE) @Getter public class StudyMeetingSchedule { @@ -15,16 +19,24 @@ public class StudyMeetingSchedule { private final Repetition repetition; @Getter - @AllArgsConstructor(staticName = "of") public static class Repetition { private final RepetitionType type; private final List dates; - } - public static StudyMeetingSchedule of(LocalTime time, Repetition repetition) { - return new StudyMeetingSchedule(time, repetition); + @Builder + public Repetition(RepetitionType type, List dates) { + validateRepetition(type, dates); + this.type = type; + this.dates = type.equals(RepetitionType.WEEKLY) ? null : dates; + } + + private void validateRepetition(RepetitionType type, List dates) { + if(!type.equals(RepetitionType.DAILY) && dates == null) { + throw new InvalidRepetitionDatesException(type.toString()); + } + } } public LocalTime getTime() { diff --git a/src/main/java/com/stumeet/server/study/domain/exception/InvalidRepetitionDatesException.java b/src/main/java/com/stumeet/server/study/domain/exception/InvalidRepetitionDatesException.java new file mode 100644 index 00000000..08b55388 --- /dev/null +++ b/src/main/java/com/stumeet/server/study/domain/exception/InvalidRepetitionDatesException.java @@ -0,0 +1,10 @@ +package com.stumeet.server.study.domain.exception; + +import com.stumeet.server.common.exception.model.InvalidStateException; +import com.stumeet.server.common.response.ErrorCode; + +public class InvalidRepetitionDatesException extends InvalidStateException { + public InvalidRepetitionDatesException(String repetitionType) { + super("유효하지 않은 반복일 값 입니다. 반복유형: " + repetitionType, ErrorCode.METHOD_ARGUMENT_NOT_VALID_EXCEPTION); + } +} From b8aee97c7fc323758703c7fad8c9ca49940d4b86 Mon Sep 17 00:00:00 2001 From: Lee ChanMi Date: Wed, 3 Apr 2024 18:26:33 +0900 Subject: [PATCH 18/35] =?UTF-8?q?:goal=5Fnet:=20[STMT-62]=20InvalidRepetit?= =?UTF-8?q?ionDatesException=20=EB=B6=80=EB=AA=A8=20=ED=81=B4=EB=9E=98?= =?UTF-8?q?=EC=8A=A4=EB=A5=BC=20BadRequestException=EC=9C=BC=EB=A1=9C=20?= =?UTF-8?q?=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../common/exception/model/BadRequestException.java | 13 +++++++++++++ .../exception/InvalidRepetitionDatesException.java | 4 ++-- 2 files changed, 15 insertions(+), 2 deletions(-) create mode 100644 src/main/java/com/stumeet/server/common/exception/model/BadRequestException.java diff --git a/src/main/java/com/stumeet/server/common/exception/model/BadRequestException.java b/src/main/java/com/stumeet/server/common/exception/model/BadRequestException.java new file mode 100644 index 00000000..edcfe7ac --- /dev/null +++ b/src/main/java/com/stumeet/server/common/exception/model/BadRequestException.java @@ -0,0 +1,13 @@ +package com.stumeet.server.common.exception.model; + +import com.stumeet.server.common.response.ErrorCode; + +public class BadRequestException extends BusinessException{ + public BadRequestException(ErrorCode errorCode) { + super(errorCode); + } + + public BadRequestException(String message, ErrorCode errorCode) { + super(message, errorCode); + } +} diff --git a/src/main/java/com/stumeet/server/study/domain/exception/InvalidRepetitionDatesException.java b/src/main/java/com/stumeet/server/study/domain/exception/InvalidRepetitionDatesException.java index 08b55388..a9714a90 100644 --- a/src/main/java/com/stumeet/server/study/domain/exception/InvalidRepetitionDatesException.java +++ b/src/main/java/com/stumeet/server/study/domain/exception/InvalidRepetitionDatesException.java @@ -1,9 +1,9 @@ package com.stumeet.server.study.domain.exception; -import com.stumeet.server.common.exception.model.InvalidStateException; +import com.stumeet.server.common.exception.model.BadRequestException; import com.stumeet.server.common.response.ErrorCode; -public class InvalidRepetitionDatesException extends InvalidStateException { +public class InvalidRepetitionDatesException extends BadRequestException { public InvalidRepetitionDatesException(String repetitionType) { super("유효하지 않은 반복일 값 입니다. 반복유형: " + repetitionType, ErrorCode.METHOD_ARGUMENT_NOT_VALID_EXCEPTION); } From 313f1f974d7238806ec9c7a54ada86c8c882749a Mon Sep 17 00:00:00 2001 From: Lee ChanMi Date: Wed, 3 Apr 2024 18:28:44 +0900 Subject: [PATCH 19/35] =?UTF-8?q?:goal=5Fnet:=20[STMT-62]=20studyTag?= =?UTF-8?q?=EC=99=80=20repetition=20dates=EA=B0=80=20null=EC=9D=BC=20?= =?UTF-8?q?=EA=B2=BD=EC=9A=B0=20mapping=20=EC=98=88=EC=99=B8=20=EC=B2=98?= =?UTF-8?q?=EB=A6=AC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../MeetingRepetitionPersistenceMapper.java | 6 +++++- .../mapper/StudyPersistenceMapper.java | 15 +++++++++------ .../mapper/StudyTagPersistenceMapper.java | 13 ++++++++----- .../port/in/mapper/StudyTagsUseCaseMapper.java | 6 +++--- .../application/service/StudyCreateService.java | 5 ++++- 5 files changed, 29 insertions(+), 16 deletions(-) diff --git a/src/main/java/com/stumeet/server/study/adapter/out/persistance/mapper/MeetingRepetitionPersistenceMapper.java b/src/main/java/com/stumeet/server/study/adapter/out/persistance/mapper/MeetingRepetitionPersistenceMapper.java index 7c0d4068..2761d8a7 100644 --- a/src/main/java/com/stumeet/server/study/adapter/out/persistance/mapper/MeetingRepetitionPersistenceMapper.java +++ b/src/main/java/com/stumeet/server/study/adapter/out/persistance/mapper/MeetingRepetitionPersistenceMapper.java @@ -22,8 +22,12 @@ public StudyMeetingSchedule.Repetition toDomain(String meetingRepetition) { } public String toColumn(StudyMeetingSchedule.Repetition repetition) { + String dates = repetition.getDates() != null + ? String.join(REPEAT_DELIMITER, repetition.getDates()) + : null; + return repetition.getType().toString() + REPEAT_DELIMITER - + String.join(REPEAT_DELIMITER, repetition.getDates()); + + dates; } } diff --git a/src/main/java/com/stumeet/server/study/adapter/out/persistance/mapper/StudyPersistenceMapper.java b/src/main/java/com/stumeet/server/study/adapter/out/persistance/mapper/StudyPersistenceMapper.java index c81c2bda..62b0ed57 100644 --- a/src/main/java/com/stumeet/server/study/adapter/out/persistance/mapper/StudyPersistenceMapper.java +++ b/src/main/java/com/stumeet/server/study/adapter/out/persistance/mapper/StudyPersistenceMapper.java @@ -25,13 +25,16 @@ public Study toDomain(StudyJpaEntity entity) { .region(entity.getRegion()) .intro(entity.getIntro()) .rule(entity.getRule()) - .period(StudyPeriod.of(entity.getStartDate(), entity.getEndDate())) - .headcount(StudyHeadCount.from(entity.getHeadcount())) + .period(StudyPeriod.builder() + .startDate(entity.getStartDate()) + .endDate(entity.getEndDate()) + .build()) + .headcount(new StudyHeadCount(entity.getHeadcount())) .image(entity.getImage()) - .meetingSchedule( - StudyMeetingSchedule.of( - entity.getMeetingTime(), - meetingRepetitionPersistenceMapper.toDomain(entity.getMeetingRepetition()))) + .meetingSchedule(StudyMeetingSchedule.builder() + .time(entity.getMeetingTime()) + .repetition(meetingRepetitionPersistenceMapper.toDomain(entity.getMeetingRepetition())) + .build()) .isFinished(entity.getIsFinished()) .isDeleted(entity.getIsDeleted()) .build(); diff --git a/src/main/java/com/stumeet/server/study/adapter/out/persistance/mapper/StudyTagPersistenceMapper.java b/src/main/java/com/stumeet/server/study/adapter/out/persistance/mapper/StudyTagPersistenceMapper.java index 20421fd6..b79ed765 100644 --- a/src/main/java/com/stumeet/server/study/adapter/out/persistance/mapper/StudyTagPersistenceMapper.java +++ b/src/main/java/com/stumeet/server/study/adapter/out/persistance/mapper/StudyTagPersistenceMapper.java @@ -11,22 +11,25 @@ public class StudyTagPersistenceMapper { public List toDomains(List entities) { - return entities - .stream() + return entities != null + ? entities.stream() .map(tagEntity -> StudyTag.builder() .id(tagEntity.getId()) .name(tagEntity.getName()) .build()) - .toList(); + .toList() + : null; } public List toEntities(List domains, Long studyDomainId) { - return domains.stream() + return domains != null + ? domains.stream() .map(tagDomain -> StudyTagJpaEntity.builder() .id(tagDomain.getId()) .studyDomainId(studyDomainId) .name(tagDomain.getName()) .build()) - .toList(); + .toList() + : null; } } diff --git a/src/main/java/com/stumeet/server/study/application/port/in/mapper/StudyTagsUseCaseMapper.java b/src/main/java/com/stumeet/server/study/application/port/in/mapper/StudyTagsUseCaseMapper.java index 000fd00e..f6be0b89 100644 --- a/src/main/java/com/stumeet/server/study/application/port/in/mapper/StudyTagsUseCaseMapper.java +++ b/src/main/java/com/stumeet/server/study/application/port/in/mapper/StudyTagsUseCaseMapper.java @@ -10,9 +10,9 @@ public class StudyTagsUseCaseMapper { public List toDomains(List tags) { - return tags.stream() - .map(this::toDomain) - .toList(); + return tags != null + ? tags.stream().map(this::toDomain).toList() + : null; } private StudyTag toDomain(String tag) { diff --git a/src/main/java/com/stumeet/server/study/application/service/StudyCreateService.java b/src/main/java/com/stumeet/server/study/application/service/StudyCreateService.java index da4d7f38..283649ef 100644 --- a/src/main/java/com/stumeet/server/study/application/service/StudyCreateService.java +++ b/src/main/java/com/stumeet/server/study/application/service/StudyCreateService.java @@ -58,7 +58,10 @@ public Long create(StudyCreateCommand command, Member member) { private StudyDomain createStudyDomain(StudyDomain studyDomain) { StudyDomain created = studyDomainCommandPort.save(studyDomain); - studyTagCommandPort.saveAll(created.getStudyTags(), created.getId()); + + if (created.getStudyTags() != null) { + studyTagCommandPort.saveAll(created.getStudyTags(), created.getId()); + } return created; } From 540aa6f2c2311baceead65adbb1532adfd6eb7a2 Mon Sep 17 00:00:00 2001 From: Lee ChanMi Date: Wed, 3 Apr 2024 18:29:34 +0900 Subject: [PATCH 20/35] =?UTF-8?q?:bug:=20[STMT-62]=20Repetition=20validati?= =?UTF-8?q?on=20=EB=A1=9C=EC=A7=81=20=EB=B2=84=EA=B7=B8=20=EC=88=98?= =?UTF-8?q?=EC=A0=95:=20=EB=B0=98=EB=B3=B5=20=ED=83=80=EC=9E=85=20WEEKLY?= =?UTF-8?q?=20->=20DAILY?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../com/stumeet/server/study/domain/StudyMeetingSchedule.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/com/stumeet/server/study/domain/StudyMeetingSchedule.java b/src/main/java/com/stumeet/server/study/domain/StudyMeetingSchedule.java index 4a843834..19592dc0 100644 --- a/src/main/java/com/stumeet/server/study/domain/StudyMeetingSchedule.java +++ b/src/main/java/com/stumeet/server/study/domain/StudyMeetingSchedule.java @@ -29,7 +29,7 @@ public static class Repetition { public Repetition(RepetitionType type, List dates) { validateRepetition(type, dates); this.type = type; - this.dates = type.equals(RepetitionType.WEEKLY) ? null : dates; + this.dates = type.equals(RepetitionType.DAILY) ? null : dates; } private void validateRepetition(RepetitionType type, List dates) { From 47bf5112cd516efa04a5c00a132968361e393596 Mon Sep 17 00:00:00 2001 From: Lee ChanMi Date: Wed, 3 Apr 2024 18:30:37 +0900 Subject: [PATCH 21/35] =?UTF-8?q?:test=5Ftube:=20[STMT-62]=20StudyMeetingS?= =?UTF-8?q?chedule=20test=20=EC=BD=94=EB=93=9C=20=EC=9E=91=EC=84=B1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../domain/StudyMeetingScheduleTest.java | 97 +++++++++++++++++++ 1 file changed, 97 insertions(+) create mode 100644 src/test/java/com/stumeet/server/study/domain/StudyMeetingScheduleTest.java diff --git a/src/test/java/com/stumeet/server/study/domain/StudyMeetingScheduleTest.java b/src/test/java/com/stumeet/server/study/domain/StudyMeetingScheduleTest.java new file mode 100644 index 00000000..431bc0ba --- /dev/null +++ b/src/test/java/com/stumeet/server/study/domain/StudyMeetingScheduleTest.java @@ -0,0 +1,97 @@ +package com.stumeet.server.study.domain; + +import static org.assertj.core.api.Assertions.*; +import static org.assertj.core.api.Assertions.assertThatCode; + +import java.time.LocalTime; +import java.util.List; + +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Nested; +import org.junit.jupiter.api.Test; + +import com.stumeet.server.study.domain.exception.InvalidRepetitionDatesException; +import com.stumeet.server.template.UnitTest; + +class StudyMeetingScheduleTest extends UnitTest { + + private final LocalTime meetingTime = LocalTime.of(18, 30); + + @Nested + @DisplayName("[단위 테스트] 스터디 일정 생성") + class create { + + @Test + @DisplayName("[성공] 반복 유형이 DAILY일 때, 인수 dates에 null을 전달 받았을 경우 생성에 성공한다.") + void weeklyTypeNullDatesSuccessTest() { + StudyMeetingSchedule.Repetition dailyRepetition = StudyMeetingSchedule.Repetition.builder() + .type(RepetitionType.DAILY) + .dates(null) + .build(); + + assertThatCode(() -> StudyMeetingSchedule.builder() + .time(meetingTime) + .repetition(dailyRepetition) + .build()) + .doesNotThrowAnyException(); + } + + @Test + @DisplayName("[성공] 반복 유형이 DAILY일 때, 인수 dates에 null이 아닌 값을 전달 받았을 경우 생성에 성공한다.") + void weeklyTypeInvalidDatesSuccessTest() { + StudyMeetingSchedule.Repetition dailyRepetitionWithNonNullDates = StudyMeetingSchedule.Repetition.builder() + .type(RepetitionType.DAILY) + .dates(List.of("월", "화", "수", "목", "금", "토", "일")) + .build(); + + assertThat(StudyMeetingSchedule.builder() + .time(meetingTime) + .repetition(dailyRepetitionWithNonNullDates) + .build() + .getRepetitionDates()) + .isNull(); + } + + @Test + @DisplayName("[성공] 반복 유형이 DAILY가 아닐 때, 유효한 값을 전달 받았을 경우 생성에 성공한다.") + void otherTypesSuccessTest() { + StudyMeetingSchedule.Repetition weeklyRepetition = StudyMeetingSchedule.Repetition.builder() + .type(RepetitionType.WEEKLY) + .dates(List.of("수", "금")) + .build(); + + assertThatCode(() -> StudyMeetingSchedule.builder() + .time(meetingTime) + .repetition(weeklyRepetition) + .build()) + .doesNotThrowAnyException(); + + StudyMeetingSchedule.Repetition monthlyRepetition = StudyMeetingSchedule.Repetition.builder() + .type(RepetitionType.MONTHLY) + .dates(List.of("10", "20", "30")) + .build(); + + assertThatCode(() -> StudyMeetingSchedule.builder() + .time(meetingTime) + .repetition(monthlyRepetition) + .build()) + .doesNotThrowAnyException(); + } + + @Test + @DisplayName("[실패] 반복 타입이 DAILY가 아닌 경우 반복일이 null이면 테스트에 실패한다.") + void invalidDatesFailTest() { + assertThatThrownBy(() -> StudyMeetingSchedule.Repetition.builder() + .type(RepetitionType.WEEKLY) + .dates(null) + .build()) + .isInstanceOf(InvalidRepetitionDatesException.class); + + assertThatThrownBy(() -> StudyMeetingSchedule.Repetition.builder() + .type(RepetitionType.MONTHLY) + .dates(null) + .build()) + .isInstanceOf(InvalidRepetitionDatesException.class); + } + } +} \ No newline at end of file From 9a7d7cd7646db2dcdf822121b0056fb2782d92a7 Mon Sep 17 00:00:00 2001 From: Lee ChanMi Date: Wed, 3 Apr 2024 18:30:52 +0900 Subject: [PATCH 22/35] =?UTF-8?q?:test=5Ftube:=20[STMT-62]=20StudyCreateAp?= =?UTF-8?q?i=20test=20=EC=BD=94=EB=93=9C=20=EC=9E=91=EC=84=B1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../adapter/in/web/StudyCreateApiTest.java | 109 +++++++++++++++--- 1 file changed, 94 insertions(+), 15 deletions(-) diff --git a/src/test/java/com/stumeet/server/study/adapter/in/web/StudyCreateApiTest.java b/src/test/java/com/stumeet/server/study/adapter/in/web/StudyCreateApiTest.java index 4e6fdf9e..fc68fa27 100644 --- a/src/test/java/com/stumeet/server/study/adapter/in/web/StudyCreateApiTest.java +++ b/src/test/java/com/stumeet/server/study/adapter/in/web/StudyCreateApiTest.java @@ -21,6 +21,7 @@ import com.stumeet.server.stub.StudyStub; import com.stumeet.server.stub.TokenStub; import com.stumeet.server.study.application.port.in.command.StudyCreateCommand; +import com.stumeet.server.study.domain.RepetitionType; import com.stumeet.server.template.ApiTest; class StudyCreateApiTest extends ApiTest { @@ -126,22 +127,100 @@ void successWithoutImageFile() throws Exception { return http; }; mockMvc.perform(multipart(path) - .with(postMethod) - .header(AuthenticationHeader.ACCESS_TOKEN.getName(), TokenStub.getMockAccessToken()) - .queryParam("studyFieldId", String.valueOf(request.studyFieldId())) - .queryParam("name", request.name()) - .queryParam("intro", request.intro()) - .queryParam("region", request.region()) - .queryParam("rule", request.rule()) - .queryParam("startDate", String.valueOf(request.startDate())) - .queryParam("endDate", String.valueOf(request.endDate())) - .queryParam("meetingTime", String.valueOf(request.meetingTime())) - .queryParam("meetingRepetitionType", request.meetingRepetitionType().name()) - .queryParam("meetingRepetitionDates", String.valueOf(request.meetingRepetitionDates())) - .queryParam("studyTags", String.valueOf(request.studyTags())) - .contentType(MediaType.MULTIPART_FORM_DATA) - .accept(MediaType.APPLICATION_JSON)) + .with(postMethod) + .header(AuthenticationHeader.ACCESS_TOKEN.getName(), TokenStub.getMockAccessToken()) + .queryParam("studyFieldId", String.valueOf(request.studyFieldId())) + .queryParam("name", request.name()) + .queryParam("intro", request.intro()) + .queryParam("region", request.region()) + .queryParam("rule", request.rule()) + .queryParam("startDate", String.valueOf(request.startDate())) + .queryParam("endDate", String.valueOf(request.endDate())) + .queryParam("meetingTime", String.valueOf(request.meetingTime())) + .queryParam("meetingRepetitionType", request.meetingRepetitionType().name()) + .queryParam("meetingRepetitionDates", String.valueOf(request.meetingRepetitionDates())) + .queryParam("studyTags", String.valueOf(request.studyTags())) + .contentType(MediaType.MULTIPART_FORM_DATA) + .accept(MediaType.APPLICATION_JSON)) .andExpect(status().isCreated()); } + + @Test + @WithMockMember + @DisplayName("[실패] 존재하지 않는 스터디 분야의 ID로 요청한 경우 스터디 생성을 실패한다.") + void failWithNotExistStudyFieldId() throws Exception { + StudyCreateCommand request = StudyStub.getStudyCreateCommand(); + int invalidStudyFieldId = 0; + + RequestPostProcessor postMethod = http -> { + http.setMethod("POST"); + return http; + }; + mockMvc.perform(multipart(path) + .file((MockMultipartFile) request.image()) + .with(postMethod) + .header(AuthenticationHeader.ACCESS_TOKEN.getName(), TokenStub.getMockAccessToken()) + .queryParam("studyFieldId", String.valueOf(invalidStudyFieldId)) + .queryParam("name", request.name()) + .queryParam("intro", request.intro()) + .queryParam("region", request.region()) + .queryParam("rule", request.rule()) + .queryParam("startDate", String.valueOf(request.startDate())) + .queryParam("endDate", String.valueOf(request.endDate())) + .queryParam("meetingTime", String.valueOf(request.meetingTime())) + .queryParam("meetingRepetitionType", request.meetingRepetitionType().name()) + .queryParam("meetingRepetitionDates", String.valueOf(request.meetingRepetitionDates())) + .queryParam("studyTags", String.valueOf(request.studyTags())) + .contentType(MediaType.MULTIPART_FORM_DATA) + .accept(MediaType.APPLICATION_JSON)) + .andExpect(status().isNotFound()) + .andDo(document("create-study/fail/study-field-not-found", + preprocessRequest(prettyPrint()), + preprocessResponse(prettyPrint()), + requestHeaders(headerWithName(AuthenticationHeader.ACCESS_TOKEN.getName()).description( + "서버로부터 전달받은 액세스 토큰")), + responseFields( + fieldWithPath("code").description("응답 상태"), + fieldWithPath("message").description("응답 메시지") + ))); + } + + @Test + @WithMockMember + @DisplayName("[실패] 유효하지 않은 반복 일정 값으로 요청한 경우 스터디 생성을 실패한다.") + void failWithInvalidStudyMeetingSchedule() throws Exception { + StudyCreateCommand request = StudyStub.getStudyCreateCommand(); + + RequestPostProcessor postMethod = http -> { + http.setMethod("POST"); + return http; + }; + mockMvc.perform(multipart(path) + .file((MockMultipartFile) request.image()) + .with(postMethod) + .header(AuthenticationHeader.ACCESS_TOKEN.getName(), TokenStub.getMockAccessToken()) + .queryParam("studyFieldId", String.valueOf(request.studyFieldId())) + .queryParam("name", request.name()) + .queryParam("intro", request.intro()) + .queryParam("region", request.region()) + .queryParam("rule", request.rule()) + .queryParam("startDate", String.valueOf(request.startDate())) + .queryParam("endDate", String.valueOf(request.endDate())) + .queryParam("meetingTime", String.valueOf(request.meetingTime())) + .queryParam("meetingRepetitionType", RepetitionType.WEEKLY.toString()) + .queryParam("studyTags", String.valueOf(request.studyTags())) + .contentType(MediaType.MULTIPART_FORM_DATA) + .accept(MediaType.APPLICATION_JSON)) + .andExpect(status().isBadRequest()) + .andDo(document("create-study/fail/invalid-study-meeting-schedule", + preprocessRequest(prettyPrint()), + preprocessResponse(prettyPrint()), + requestHeaders(headerWithName(AuthenticationHeader.ACCESS_TOKEN.getName()).description( + "서버로부터 전달받은 액세스 토큰")), + responseFields( + fieldWithPath("code").description("응답 상태"), + fieldWithPath("message").description("응답 메시지") + ))); + } } } \ No newline at end of file From 142baa53805bd551faac9c8ae9a58b49e27e4869 Mon Sep 17 00:00:00 2001 From: Lee ChanMi Date: Wed, 3 Apr 2024 18:49:12 +0900 Subject: [PATCH 23/35] =?UTF-8?q?:white=5Fcheck=5Fmark:=20[STMT-62]=20?= =?UTF-8?q?=EB=A6=AC=EC=8A=A4=ED=8A=B8=EB=A5=BC=20=EB=AC=B8=EC=9E=90?= =?UTF-8?q?=EC=97=B4=EB=A1=9C=20=EC=A0=84=EB=8B=AC=ED=95=9C=20=EA=B2=BD?= =?UTF-8?q?=EC=9A=B0=20=EB=8C=80=EA=B4=84=ED=98=B8=EA=B0=80=20=EA=B2=B0?= =?UTF-8?q?=EA=B3=BC=EC=97=90=20=ED=8F=AC=ED=95=A8=EB=90=98=EB=8A=94=20?= =?UTF-8?q?=EC=97=90=EB=9F=AC=20=ED=95=B4=EA=B2=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../adapter/in/web/StudyCreateApiTest.java | 23 +++++++++---------- 1 file changed, 11 insertions(+), 12 deletions(-) diff --git a/src/test/java/com/stumeet/server/study/adapter/in/web/StudyCreateApiTest.java b/src/test/java/com/stumeet/server/study/adapter/in/web/StudyCreateApiTest.java index fc68fa27..2290b5b3 100644 --- a/src/test/java/com/stumeet/server/study/adapter/in/web/StudyCreateApiTest.java +++ b/src/test/java/com/stumeet/server/study/adapter/in/web/StudyCreateApiTest.java @@ -21,7 +21,6 @@ import com.stumeet.server.stub.StudyStub; import com.stumeet.server.stub.TokenStub; import com.stumeet.server.study.application.port.in.command.StudyCreateCommand; -import com.stumeet.server.study.domain.RepetitionType; import com.stumeet.server.template.ApiTest; class StudyCreateApiTest extends ApiTest { @@ -54,9 +53,9 @@ void successTest() throws Exception { .queryParam("startDate", String.valueOf(request.startDate())) .queryParam("endDate", String.valueOf(request.endDate())) .queryParam("meetingTime", String.valueOf(request.meetingTime())) - .queryParam("meetingRepetitionType", request.meetingRepetitionType().name()) - .queryParam("meetingRepetitionDates", String.valueOf(request.meetingRepetitionDates())) - .queryParam("studyTags", String.valueOf(request.studyTags())) + .queryParam("meetingRepetitionType", request.meetingRepetitionType().toString()) + .queryParam("meetingRepetitionDates", request.meetingRepetitionDates().toArray(String[]::new)) + .queryParam("studyTags", request.studyTags().toArray(String[]::new)) .contentType(MediaType.MULTIPART_FORM_DATA) .accept(MediaType.APPLICATION_JSON)) .andExpect(status().isCreated()) @@ -137,9 +136,9 @@ void successWithoutImageFile() throws Exception { .queryParam("startDate", String.valueOf(request.startDate())) .queryParam("endDate", String.valueOf(request.endDate())) .queryParam("meetingTime", String.valueOf(request.meetingTime())) - .queryParam("meetingRepetitionType", request.meetingRepetitionType().name()) - .queryParam("meetingRepetitionDates", String.valueOf(request.meetingRepetitionDates())) - .queryParam("studyTags", String.valueOf(request.studyTags())) + .queryParam("meetingRepetitionType", request.meetingRepetitionType().toString()) + .queryParam("meetingRepetitionDates", request.meetingRepetitionDates().toArray(String[]::new)) + .queryParam("studyTags", request.studyTags().toArray(String[]::new)) .contentType(MediaType.MULTIPART_FORM_DATA) .accept(MediaType.APPLICATION_JSON)) .andExpect(status().isCreated()); @@ -168,9 +167,9 @@ void failWithNotExistStudyFieldId() throws Exception { .queryParam("startDate", String.valueOf(request.startDate())) .queryParam("endDate", String.valueOf(request.endDate())) .queryParam("meetingTime", String.valueOf(request.meetingTime())) - .queryParam("meetingRepetitionType", request.meetingRepetitionType().name()) - .queryParam("meetingRepetitionDates", String.valueOf(request.meetingRepetitionDates())) - .queryParam("studyTags", String.valueOf(request.studyTags())) + .queryParam("meetingRepetitionType", request.meetingRepetitionType().toString()) + .queryParam("meetingRepetitionDates", request.meetingRepetitionDates().toArray(String[]::new)) + .queryParam("studyTags", request.studyTags().toArray(String[]::new)) .contentType(MediaType.MULTIPART_FORM_DATA) .accept(MediaType.APPLICATION_JSON)) .andExpect(status().isNotFound()) @@ -207,8 +206,8 @@ void failWithInvalidStudyMeetingSchedule() throws Exception { .queryParam("startDate", String.valueOf(request.startDate())) .queryParam("endDate", String.valueOf(request.endDate())) .queryParam("meetingTime", String.valueOf(request.meetingTime())) - .queryParam("meetingRepetitionType", RepetitionType.WEEKLY.toString()) - .queryParam("studyTags", String.valueOf(request.studyTags())) + .queryParam("meetingRepetitionType", request.meetingRepetitionType().toString()) + .queryParam("studyTags", request.studyTags().toArray(String[]::new)) .contentType(MediaType.MULTIPART_FORM_DATA) .accept(MediaType.APPLICATION_JSON)) .andExpect(status().isBadRequest()) From c21e8c54d01f247a678782de6ba7455595097a54 Mon Sep 17 00:00:00 2001 From: Lee ChanMi Date: Wed, 3 Apr 2024 18:49:38 +0900 Subject: [PATCH 24/35] =?UTF-8?q?:memo:=20[STMT-62]=20=EC=8A=A4=ED=84=B0?= =?UTF-8?q?=EB=94=94=20=EC=83=9D=EC=84=B1=20API=20=EB=AA=85=EC=84=B8?= =?UTF-8?q?=EC=84=9C=20=EC=9E=91=EC=84=B1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/docs/asciidoc/index.adoc | 28 ++++++++++++++++++++++++++++ 1 file changed, 28 insertions(+) diff --git a/src/docs/asciidoc/index.adoc b/src/docs/asciidoc/index.adoc index 4ca87aad..480dfbeb 100644 --- a/src/docs/asciidoc/index.adoc +++ b/src/docs/asciidoc/index.adoc @@ -225,6 +225,34 @@ include::{snippets}/get-study-detail/fail/not-found/response-body.adoc[] include::{snippets}/get-study-detail/fail/not-found/response-fields.adoc[] +=== 스터디 생성 + +스터디를 생성하는 API 입니다. + +==== POST /api/v1/studies + +===== 요청 +include::{snippets}/create-study/success/http-request.adoc[] +include::{snippets}/create-study/success/request-headers.adoc[] + +===== 응답 성공 (200) + +include::{snippets}/create-study/success/response-body.adoc[] +include::{snippets}/create-study/success/response-fields.adoc[] + +===== 응답 실패 (404) + +.존재하지 않는 스터디 분야 ID를 요청한 경우 + +include::{snippets}/create-study/fail/study-field-not-found/response-body.adoc[] +include::{snippets}/create-study/fail/study-field-not-found/response-fields.adoc[] + +.일정 반복 유형 DAILY일 때를 제외하고 반복일을 null 값으로 요청한 경우 + +include::{snippets}/create-study/fail/invalid-study-meeting-schedule/response-body.adoc[] +include::{snippets}/create-study/fail/invalid-study-meeting-schedule/response-fields.adoc[] + + == 스터디 멤버 관리 === 스터디 멤버 조회 From 6e9986d349d58a9d0bf7245a4dd3d94f454e0afe Mon Sep 17 00:00:00 2001 From: Lee ChanMi Date: Mon, 8 Apr 2024 09:04:55 +0900 Subject: [PATCH 25/35] =?UTF-8?q?:construction:=20[STMT-62]=20=EB=A6=AC?= =?UTF-8?q?=EB=B7=B0=20=EC=9E=90=EC=9E=98=ED=95=9C=20=EC=88=98=EC=A0=95?= =?UTF-8?q?=EC=82=AC=ED=95=AD=20=EB=B0=98=EC=98=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../exception/model/BadRequestException.java | 2 +- .../server/common/response/ErrorCode.java | 89 +++++++++---------- .../server/common/response/SuccessCode.java | 11 ++- .../study/adapter/in/web/StudyCreateApi.java | 1 - .../study/adapter/in/web/StudyQueryApi.java | 2 +- 5 files changed, 55 insertions(+), 50 deletions(-) diff --git a/src/main/java/com/stumeet/server/common/exception/model/BadRequestException.java b/src/main/java/com/stumeet/server/common/exception/model/BadRequestException.java index edcfe7ac..409cde8e 100644 --- a/src/main/java/com/stumeet/server/common/exception/model/BadRequestException.java +++ b/src/main/java/com/stumeet/server/common/exception/model/BadRequestException.java @@ -2,7 +2,7 @@ import com.stumeet.server.common.response.ErrorCode; -public class BadRequestException extends BusinessException{ +public class BadRequestException extends BusinessException { public BadRequestException(ErrorCode errorCode) { super(errorCode); } diff --git a/src/main/java/com/stumeet/server/common/response/ErrorCode.java b/src/main/java/com/stumeet/server/common/response/ErrorCode.java index bb54fa6a..b9da94fd 100644 --- a/src/main/java/com/stumeet/server/common/response/ErrorCode.java +++ b/src/main/java/com/stumeet/server/common/response/ErrorCode.java @@ -3,64 +3,63 @@ import lombok.AccessLevel; import lombok.AllArgsConstructor; import lombok.Getter; + import org.springframework.http.HttpStatus; @Getter @AllArgsConstructor(access = AccessLevel.PRIVATE) public enum ErrorCode { - /* + /* 400 - BAD REQUEST */ - VALIDATION_REQUEST_EXCEPTION(HttpStatus.BAD_REQUEST, "잘못된 요청입니다."), - BIND_EXCEPTION(HttpStatus.BAD_REQUEST, "요청 값을 바인딩하는 과정에서 오류가 발생하였습니다."), - METHOD_ARGUMENT_NOT_VALID_EXCEPTION(HttpStatus.BAD_REQUEST, "요청 값이 검증되지 않은 값 입니다."), - METHOD_ARGUMENT_TYPE_MISMATCH_EXCEPTION(HttpStatus.BAD_REQUEST, "요청 값의 타입이 잘못되었습니다."), - INVALID_FORMAT_EXCEPTION(HttpStatus.BAD_REQUEST, "요청 값이 유효하지 않은 데이터입니다."), - DUPLICATE_NICKNAME_EXCEPTION(HttpStatus.BAD_REQUEST, "닉네임이 중복되었습니다."), - NOT_EXIST_EXCEPTION(HttpStatus.BAD_REQUEST, "요청으로 전달한 값이 존재하지 않습니다."), - NOT_MATCHED_TOKEN_EXCEPTION(HttpStatus.BAD_REQUEST, "요청으로 전달한 토큰과 매칭되는 토큰이 없습니다."), - NOT_MATCHED_REFRESH_TOKEN_EXCEPTION(HttpStatus.BAD_REQUEST, "요청으로 전달한 리프레시 토큰과 서버의 리프레시 토큰이 일치하지 않습니다."), - EXPIRED_REFRESH_TOKEN_EXCEPTION(HttpStatus.BAD_REQUEST, "리프레시 토큰이 만료되었습니다."), - - INVALID_FILE_NAME_EXCEPTION(HttpStatus.BAD_REQUEST, "유효하지 않은 파일 이름입니다."), - INVALID_FILE_CONTENT_TYPE_EXCEPTION(HttpStatus.BAD_REQUEST, "유효하지 않은 파일 컨텐트 타입 입니다."), - INVALID_FILE_EXTENSION_EXCEPTION(HttpStatus.BAD_REQUEST, "유효하지 않은 파일 확장자입니다."), + VALIDATION_REQUEST_EXCEPTION(HttpStatus.BAD_REQUEST, "잘못된 요청입니다."), + BIND_EXCEPTION(HttpStatus.BAD_REQUEST, "요청 값을 바인딩하는 과정에서 오류가 발생하였습니다."), + METHOD_ARGUMENT_NOT_VALID_EXCEPTION(HttpStatus.BAD_REQUEST, "요청 값이 검증되지 않은 값 입니다."), + METHOD_ARGUMENT_TYPE_MISMATCH_EXCEPTION(HttpStatus.BAD_REQUEST, "요청 값의 타입이 잘못되었습니다."), + INVALID_FORMAT_EXCEPTION(HttpStatus.BAD_REQUEST, "요청 값이 유효하지 않은 데이터입니다."), + DUPLICATE_NICKNAME_EXCEPTION(HttpStatus.BAD_REQUEST, "닉네임이 중복되었습니다."), + NOT_EXIST_EXCEPTION(HttpStatus.BAD_REQUEST, "요청으로 전달한 값이 존재하지 않습니다."), + NOT_MATCHED_TOKEN_EXCEPTION(HttpStatus.BAD_REQUEST, "요청으로 전달한 토큰과 매칭되는 토큰이 없습니다."), + NOT_MATCHED_REFRESH_TOKEN_EXCEPTION(HttpStatus.BAD_REQUEST, "요청으로 전달한 리프레시 토큰과 서버의 리프레시 토큰이 일치하지 않습니다."), + EXPIRED_REFRESH_TOKEN_EXCEPTION(HttpStatus.BAD_REQUEST, "리프레시 토큰이 만료되었습니다."), + INVALID_FILE_NAME_EXCEPTION(HttpStatus.BAD_REQUEST, "유효하지 않은 파일 이름입니다."), + INVALID_FILE_CONTENT_TYPE_EXCEPTION(HttpStatus.BAD_REQUEST, "유효하지 않은 파일 컨텐트 타입 입니다."), + INVALID_FILE_EXTENSION_EXCEPTION(HttpStatus.BAD_REQUEST, "유효하지 않은 파일 확장자입니다."), - /* - 401 - UNAUTHORIZED - */ - JWT_INVALID_SIGNATURE_EXCEPTION(HttpStatus.UNAUTHORIZED, "JWT 서명이 유효하지 않습니다."), - ILLEGAL_KEY_ALGORITHM_EXCEPTION(HttpStatus.UNAUTHORIZED, "유효하지 않은 키 알고리즘입니다."), - JWT_TOKEN_PARSING_EXCEPTION(HttpStatus.UNAUTHORIZED, "JWT 토큰 파싱에 실패했습니다."), - NOT_EXIST_OAUTH_PROVIDER(HttpStatus.UNAUTHORIZED, "존재하지 않는 OAuth 제공자입니다."), + /* + 401 - UNAUTHORIZED + */ + JWT_INVALID_SIGNATURE_EXCEPTION(HttpStatus.UNAUTHORIZED, "JWT 서명이 유효하지 않습니다."), + ILLEGAL_KEY_ALGORITHM_EXCEPTION(HttpStatus.UNAUTHORIZED, "유효하지 않은 키 알고리즘입니다."), + JWT_TOKEN_PARSING_EXCEPTION(HttpStatus.UNAUTHORIZED, "JWT 토큰 파싱에 실패했습니다."), + NOT_EXIST_OAUTH_PROVIDER(HttpStatus.UNAUTHORIZED, "존재하지 않는 OAuth 제공자입니다."), - /* - 403 - FORBIDDEN - */ - ACCESS_DENIED_EXCEPTION(HttpStatus.FORBIDDEN, "유효하지 않은 요청입니다."), - STUDY_MEMBER_NOT_JOINED_EXCEPTION(HttpStatus.FORBIDDEN, "스터디에 가입한 멤버가 아닙니다."), + /* + 403 - FORBIDDEN + */ + ACCESS_DENIED_EXCEPTION(HttpStatus.FORBIDDEN, "유효하지 않은 요청입니다."), + STUDY_MEMBER_NOT_JOINED_EXCEPTION(HttpStatus.FORBIDDEN, "스터디에 가입한 멤버가 아닙니다."), - /* - 404 - NOT FOUND - */ - STUDY_NOT_FOUND(HttpStatus.NOT_FOUND, "존재하지 않는 스터디 입니다."), - MEMBER_NOT_FOUND(HttpStatus.NOT_FOUND, "존재하지 않는 멤버 입니다."), - STUDY_FIELD_NOT_FOUND(HttpStatus.NOT_FOUND, "존재하지 않는 스터디 분야 입니다."), + /* + 404 - NOT FOUND + */ + STUDY_NOT_FOUND(HttpStatus.NOT_FOUND, "존재하지 않는 스터디 입니다."), + MEMBER_NOT_FOUND(HttpStatus.NOT_FOUND, "존재하지 않는 멤버 입니다."), + STUDY_FIELD_NOT_FOUND(HttpStatus.NOT_FOUND, "존재하지 않는 스터디 분야 입니다."), - /* - 500 - INTERNAL SERVER ERROR - */ - INTERNAL_SERVER_ERROR(HttpStatus.INTERNAL_SERVER_ERROR, "서버 내부에서 에러가 발생하였습니다."), - UPLOAD_FILE_FAIL_ERROR(HttpStatus.INTERNAL_SERVER_ERROR, "파일 업로드에 실패하였습니다."), - NOT_IMPLEMENTED_ERROR(HttpStatus.INTERNAL_SERVER_ERROR, "구현되지 않은 메서드를 사용했습니다.") - ; + /* + 500 - INTERNAL SERVER ERROR + */ + INTERNAL_SERVER_ERROR(HttpStatus.INTERNAL_SERVER_ERROR, "서버 내부에서 에러가 발생하였습니다."), + UPLOAD_FILE_FAIL_ERROR(HttpStatus.INTERNAL_SERVER_ERROR, "파일 업로드에 실패하였습니다."), + NOT_IMPLEMENTED_ERROR(HttpStatus.INTERNAL_SERVER_ERROR, "구현되지 않은 메서드를 사용했습니다."); - private final HttpStatus httpStatus; - private final String message; + private final HttpStatus httpStatus; + private final String message; - public int getHttpStatusCode() { - return httpStatus.value(); - } + public int getHttpStatusCode() { + return httpStatus.value(); + } } diff --git a/src/main/java/com/stumeet/server/common/response/SuccessCode.java b/src/main/java/com/stumeet/server/common/response/SuccessCode.java index 90c47b1a..48067594 100644 --- a/src/main/java/com/stumeet/server/common/response/SuccessCode.java +++ b/src/main/java/com/stumeet/server/common/response/SuccessCode.java @@ -9,11 +9,18 @@ @AllArgsConstructor(access = AccessLevel.PRIVATE) public enum SuccessCode { + /** + * 200 - OK + */ GET_SUCCESS(HttpStatus.OK, "조회에 성공했습니다."), + STUDY_LEAVE_SUCCESS(HttpStatus.OK, "스터디 탈퇴에 성공했습니다."), + + /** + * 201 - CREATED + */ POST_SUCCESS(HttpStatus.CREATED, "생성에 성공했습니다."), SIGN_UP_SUCCESS(HttpStatus.CREATED, "회원가입에 성공했습니다."), - FILE_UPLOAD_SUCCESS(HttpStatus.CREATED, "파일 업로드에 성공했습니다."), - STUDY_LEAVE_SUCCESS(HttpStatus.OK, "스터디 탈퇴에 성공했습니다."); + FILE_UPLOAD_SUCCESS(HttpStatus.CREATED, "파일 업로드에 성공했습니다."); private final HttpStatus httpStatus; private final String message; diff --git a/src/main/java/com/stumeet/server/study/adapter/in/web/StudyCreateApi.java b/src/main/java/com/stumeet/server/study/adapter/in/web/StudyCreateApi.java index 22bf56ea..802b7c6b 100644 --- a/src/main/java/com/stumeet/server/study/adapter/in/web/StudyCreateApi.java +++ b/src/main/java/com/stumeet/server/study/adapter/in/web/StudyCreateApi.java @@ -25,7 +25,6 @@ public class StudyCreateApi { private final StudyCreateUseCase studyCreateUseCase; private final StudyQueryUseCase studyQueryUseCase; - @PostMapping(consumes = "multipart/form-data", produces = "application/json") public ResponseEntity> create( @AuthenticationPrincipal LoginMember member, @Valid StudyCreateCommand request diff --git a/src/main/java/com/stumeet/server/study/adapter/in/web/StudyQueryApi.java b/src/main/java/com/stumeet/server/study/adapter/in/web/StudyQueryApi.java index 15055de7..86e33701 100644 --- a/src/main/java/com/stumeet/server/study/adapter/in/web/StudyQueryApi.java +++ b/src/main/java/com/stumeet/server/study/adapter/in/web/StudyQueryApi.java @@ -22,7 +22,7 @@ public class StudyQueryApi { @GetMapping("/{studyId}") public ResponseEntity> getStudyDetail( - @PathVariable(name = "studyId") java.lang.Long studyId + @PathVariable(name = "studyId") Long studyId ) { StudyDetailResponse response = studyQueryUseCase.getStudyDetailById(studyId); return ResponseEntity.ok(ApiResponse.success(SuccessCode.GET_SUCCESS, response)); From 53ac1f7b0ce915a80c428d1842d7863f4d5d934e Mon Sep 17 00:00:00 2001 From: Lee ChanMi Date: Mon, 8 Apr 2024 09:15:03 +0900 Subject: [PATCH 26/35] =?UTF-8?q?:construction:=20[STMT-62]=20=EA=B8=B0?= =?UTF-8?q?=ED=9A=8D=20=EC=9A=94=EA=B5=AC=EC=82=AC=ED=95=AD=EC=97=90=20?= =?UTF-8?q?=EB=94=B0=EB=9D=BC=20=EC=83=9D=EC=84=B1=EB=90=9C=20=EC=8A=A4?= =?UTF-8?q?=ED=84=B0=EB=94=94=20=EC=83=81=EC=84=B8=20=EC=A0=95=EB=B3=B4=20?= =?UTF-8?q?=EB=B0=98=ED=99=98=ED=95=98=EB=8A=94=20=EA=B8=B0=EB=8A=A5=20?= =?UTF-8?q?=EC=82=AD=EC=A0=9C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../stumeet/server/common/response/SuccessCode.java | 3 ++- .../server/study/adapter/in/web/StudyCreateApi.java | 12 +++++------- 2 files changed, 7 insertions(+), 8 deletions(-) diff --git a/src/main/java/com/stumeet/server/common/response/SuccessCode.java b/src/main/java/com/stumeet/server/common/response/SuccessCode.java index 48067594..861dd9bb 100644 --- a/src/main/java/com/stumeet/server/common/response/SuccessCode.java +++ b/src/main/java/com/stumeet/server/common/response/SuccessCode.java @@ -20,7 +20,8 @@ public enum SuccessCode { */ POST_SUCCESS(HttpStatus.CREATED, "생성에 성공했습니다."), SIGN_UP_SUCCESS(HttpStatus.CREATED, "회원가입에 성공했습니다."), - FILE_UPLOAD_SUCCESS(HttpStatus.CREATED, "파일 업로드에 성공했습니다."); + FILE_UPLOAD_SUCCESS(HttpStatus.CREATED, "파일 업로드에 성공했습니다."), + STUDY_CREATE_SUCCESS(HttpStatus.CREATED, "스터디 그룹 생성에 성공했습니다."); private final HttpStatus httpStatus; private final String message; diff --git a/src/main/java/com/stumeet/server/study/adapter/in/web/StudyCreateApi.java b/src/main/java/com/stumeet/server/study/adapter/in/web/StudyCreateApi.java index 802b7c6b..0edfc37e 100644 --- a/src/main/java/com/stumeet/server/study/adapter/in/web/StudyCreateApi.java +++ b/src/main/java/com/stumeet/server/study/adapter/in/web/StudyCreateApi.java @@ -9,10 +9,9 @@ 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.StudyCreateUseCase; -import com.stumeet.server.study.application.port.in.StudyQueryUseCase; import com.stumeet.server.study.application.port.in.command.StudyCreateCommand; -import com.stumeet.server.study.application.port.in.response.StudyDetailResponse; import jakarta.validation.Valid; import lombok.RequiredArgsConstructor; @@ -23,17 +22,16 @@ public class StudyCreateApi { private final StudyCreateUseCase studyCreateUseCase; - private final StudyQueryUseCase studyQueryUseCase; - public ResponseEntity> create( + @PostMapping + public ResponseEntity> create( @AuthenticationPrincipal LoginMember member, @Valid StudyCreateCommand request ) { - Long createdStudyId = studyCreateUseCase.create(request, member.getMember()); - StudyDetailResponse response = studyQueryUseCase.getStudyDetailById(createdStudyId); + studyCreateUseCase.create(request, member.getMember()); return new ResponseEntity<>( - ApiResponse.success(HttpStatus.CREATED.value(), "스터디 그룹 생성에 성공했습니다.", response), + ApiResponse.success(SuccessCode.STUDY_CREATE_SUCCESS), HttpStatus.CREATED); } } From 1310f2b53e814e690effbe14c5a99c5ee6a0c889 Mon Sep 17 00:00:00 2001 From: Lee ChanMi Date: Mon, 8 Apr 2024 09:31:42 +0900 Subject: [PATCH 27/35] =?UTF-8?q?:construction:=20[STMT-62]=20=EC=8A=A4?= =?UTF-8?q?=ED=84=B0=EB=94=94=20=EC=83=9D=EC=84=B1=20=EB=A9=94=EC=84=9C?= =?UTF-8?q?=EB=93=9C=20=EB=8B=A8=EC=88=9C=ED=99=94=20=EB=A6=AC=ED=8C=A9?= =?UTF-8?q?=ED=86=A0=EB=A7=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../service/FileUploadService.java | 3 +++ .../port/in/mapper/StudyUseCaseMapper.java | 9 +++++++++ .../service/StudyCreateService.java | 19 ++++++------------- 3 files changed, 18 insertions(+), 13 deletions(-) diff --git a/src/main/java/com/stumeet/server/file/application/service/FileUploadService.java b/src/main/java/com/stumeet/server/file/application/service/FileUploadService.java index 88bfae6a..9deadb7e 100644 --- a/src/main/java/com/stumeet/server/file/application/service/FileUploadService.java +++ b/src/main/java/com/stumeet/server/file/application/service/FileUploadService.java @@ -30,6 +30,9 @@ public FileUrl uploadUserProfileImage(Long userId, MultipartFile multipartFile) @Override public FileUrl uploadStudyMainImage(MultipartFile multipartFile) { + if (multipartFile == null) { + return new FileUrl(null); + } return fileCommandPort.uploadImageFile(multipartFile, STUDY_MAIN_IMAGE_DIRECTORY_PATH); } diff --git a/src/main/java/com/stumeet/server/study/application/port/in/mapper/StudyUseCaseMapper.java b/src/main/java/com/stumeet/server/study/application/port/in/mapper/StudyUseCaseMapper.java index e3d10f4d..43770745 100644 --- a/src/main/java/com/stumeet/server/study/application/port/in/mapper/StudyUseCaseMapper.java +++ b/src/main/java/com/stumeet/server/study/application/port/in/mapper/StudyUseCaseMapper.java @@ -4,6 +4,7 @@ import com.stumeet.server.study.application.port.in.response.StudyDetailResponse; import com.stumeet.server.study.domain.Study; +import com.stumeet.server.studymember.application.port.in.command.StudyMemberJoinCommand; @Component public class StudyUseCaseMapper { @@ -28,4 +29,12 @@ public StudyDetailResponse toStudyDetailResponse(Study study) { .isDeleted(study.isDeleted()) .build(); } + + public StudyMemberJoinCommand toAdminStudyMemberJoinCommand(Long memberId, Long studyId) { + return StudyMemberJoinCommand.builder() + .memberId(memberId) + .studyId(studyId) + .isAdmin(true) + .build(); + } } diff --git a/src/main/java/com/stumeet/server/study/application/service/StudyCreateService.java b/src/main/java/com/stumeet/server/study/application/service/StudyCreateService.java index 283649ef..bfa585a2 100644 --- a/src/main/java/com/stumeet/server/study/application/service/StudyCreateService.java +++ b/src/main/java/com/stumeet/server/study/application/service/StudyCreateService.java @@ -8,6 +8,7 @@ import com.stumeet.server.study.application.port.in.StudyCreateUseCase; import com.stumeet.server.study.application.port.in.command.StudyCreateCommand; import com.stumeet.server.study.application.port.in.mapper.StudyDomainUseCaseMapper; +import com.stumeet.server.study.application.port.in.mapper.StudyUseCaseMapper; import com.stumeet.server.study.application.port.out.StudyCommandPort; import com.stumeet.server.study.application.port.out.StudyDomainCommandPort; import com.stumeet.server.study.application.port.out.StudyFieldQueryPort; @@ -15,12 +16,12 @@ import com.stumeet.server.study.domain.Study; import com.stumeet.server.study.domain.StudyDomain; import com.stumeet.server.studymember.application.port.in.StudyMemberJoinUseCase; -import com.stumeet.server.studymember.application.port.in.command.StudyMemberJoinCommand; import lombok.RequiredArgsConstructor; @UseCase @RequiredArgsConstructor +@Transactional public class StudyCreateService implements StudyCreateUseCase { private final FileUploadUseCase fileUploadUseCase; @@ -31,28 +32,20 @@ public class StudyCreateService implements StudyCreateUseCase { private final StudyDomainCommandPort studyDomainCommandPort; private final StudyTagCommandPort studyTagCommandPort; + private final StudyUseCaseMapper studyUseCaseMapper; private final StudyDomainUseCaseMapper studyDomainUseCaseMapper; @Override - @Transactional public Long create(StudyCreateCommand command, Member member) { studyFieldQueryPort.checkById(command.studyFieldId()); StudyDomain studyDomainCreated = createStudyDomain(studyDomainUseCaseMapper.toDomain(command)); - String mainImageUrl = command.image() != null - ? fileUploadUseCase.uploadStudyMainImage(command.image()).url() - : null; + String mainImageUrl = fileUploadUseCase.uploadStudyMainImage(command.image()).url(); + Study study = Study.create(command, studyDomainCreated, mainImageUrl); Study studyCreated = studyCommandPort.save(study); - StudyMemberJoinCommand studyMemberJoinCommand = StudyMemberJoinCommand.builder() - .memberId(member.getId()) - .studyId(studyCreated.getId()) - .isAdmin(true) - .build(); - - memberJoinUseCase.join(studyMemberJoinCommand); - + memberJoinUseCase.join(studyUseCaseMapper.toAdminStudyMemberJoinCommand(member.getId(), studyCreated.getId())); return studyCreated.getId(); } From 436bb90c2e6d169951def4bd927ef28a80d24a79 Mon Sep 17 00:00:00 2001 From: Lee ChanMi Date: Mon, 8 Apr 2024 09:54:44 +0900 Subject: [PATCH 28/35] =?UTF-8?q?:construction:=20[STMT-62]=20=EC=8A=A4?= =?UTF-8?q?=ED=84=B0=EB=94=94=20=ED=83=9C=EA=B7=B8=EA=B0=80=20null?= =?UTF-8?q?=EC=9D=BC=20=EA=B2=BD=EC=9A=B0=20=EB=B9=88=20=EB=AC=B8=EC=9E=90?= =?UTF-8?q?=EC=97=B4=EC=9D=84=20=EB=B0=98=ED=99=98=ED=95=98=EB=8F=84?= =?UTF-8?q?=EB=A1=9D=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../out/persistance/mapper/StudyTagPersistenceMapper.java | 4 ++-- .../application/port/in/mapper/StudyTagsUseCaseMapper.java | 2 +- .../server/study/application/service/StudyCreateService.java | 2 +- .../java/com/stumeet/server/study/domain/StudyDomain.java | 4 ++++ 4 files changed, 8 insertions(+), 4 deletions(-) diff --git a/src/main/java/com/stumeet/server/study/adapter/out/persistance/mapper/StudyTagPersistenceMapper.java b/src/main/java/com/stumeet/server/study/adapter/out/persistance/mapper/StudyTagPersistenceMapper.java index b79ed765..93ab3f5e 100644 --- a/src/main/java/com/stumeet/server/study/adapter/out/persistance/mapper/StudyTagPersistenceMapper.java +++ b/src/main/java/com/stumeet/server/study/adapter/out/persistance/mapper/StudyTagPersistenceMapper.java @@ -18,7 +18,7 @@ public List toDomains(List entities) { .name(tagEntity.getName()) .build()) .toList() - : null; + : List.of(); } public List toEntities(List domains, Long studyDomainId) { @@ -30,6 +30,6 @@ public List toEntities(List domains, Long studyDoma .name(tagDomain.getName()) .build()) .toList() - : null; + : List.of(); } } diff --git a/src/main/java/com/stumeet/server/study/application/port/in/mapper/StudyTagsUseCaseMapper.java b/src/main/java/com/stumeet/server/study/application/port/in/mapper/StudyTagsUseCaseMapper.java index f6be0b89..9d300115 100644 --- a/src/main/java/com/stumeet/server/study/application/port/in/mapper/StudyTagsUseCaseMapper.java +++ b/src/main/java/com/stumeet/server/study/application/port/in/mapper/StudyTagsUseCaseMapper.java @@ -12,7 +12,7 @@ public class StudyTagsUseCaseMapper { public List toDomains(List tags) { return tags != null ? tags.stream().map(this::toDomain).toList() - : null; + : List.of(); } private StudyTag toDomain(String tag) { diff --git a/src/main/java/com/stumeet/server/study/application/service/StudyCreateService.java b/src/main/java/com/stumeet/server/study/application/service/StudyCreateService.java index bfa585a2..d60000d6 100644 --- a/src/main/java/com/stumeet/server/study/application/service/StudyCreateService.java +++ b/src/main/java/com/stumeet/server/study/application/service/StudyCreateService.java @@ -52,7 +52,7 @@ public Long create(StudyCreateCommand command, Member member) { private StudyDomain createStudyDomain(StudyDomain studyDomain) { StudyDomain created = studyDomainCommandPort.save(studyDomain); - if (created.getStudyTags() != null) { + if (created.isStudyTagNotEmpty()) { studyTagCommandPort.saveAll(created.getStudyTags(), created.getId()); } diff --git a/src/main/java/com/stumeet/server/study/domain/StudyDomain.java b/src/main/java/com/stumeet/server/study/domain/StudyDomain.java index 0e98d1ae..b0cac5a3 100644 --- a/src/main/java/com/stumeet/server/study/domain/StudyDomain.java +++ b/src/main/java/com/stumeet/server/study/domain/StudyDomain.java @@ -22,6 +22,10 @@ public String getStudyFieldName() { return studyField.getName(); } + public boolean isStudyTagNotEmpty() { + return !studyTags.isEmpty(); + } + public List getStudyTagNames() { return studyTags.stream() .map(StudyTag::getName) From e90b922710f30cf0dbd9cf743a605abf08fe8902 Mon Sep 17 00:00:00 2001 From: Lee ChanMi Date: Mon, 8 Apr 2024 09:55:32 +0900 Subject: [PATCH 29/35] =?UTF-8?q?:goal=5Fnet:=20[STMT-62]=20=EC=BB=A4?= =?UTF-8?q?=EC=8A=A4=ED=85=80=20BadRequestException=20=EC=98=88=EC=99=B8?= =?UTF-8?q?=EC=B2=98=EB=A6=AC=20=EC=B6=94=EA=B0=80:=20=EC=83=81=EC=84=B8?= =?UTF-8?q?=20=EB=A9=94=EC=8B=9C=EC=A7=80=20=EB=B0=98=ED=99=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../exception/handler/GlobalExceptionHandler.java | 12 ++++++++++++ .../exception/InvalidRepetitionDatesException.java | 2 +- 2 files changed, 13 insertions(+), 1 deletion(-) diff --git a/src/main/java/com/stumeet/server/common/exception/handler/GlobalExceptionHandler.java b/src/main/java/com/stumeet/server/common/exception/handler/GlobalExceptionHandler.java index 783626c8..cd015ade 100644 --- a/src/main/java/com/stumeet/server/common/exception/handler/GlobalExceptionHandler.java +++ b/src/main/java/com/stumeet/server/common/exception/handler/GlobalExceptionHandler.java @@ -1,6 +1,7 @@ package com.stumeet.server.common.exception.handler; import com.fasterxml.jackson.databind.exc.InvalidFormatException; +import com.stumeet.server.common.exception.model.BadRequestException; import com.stumeet.server.common.exception.model.BusinessException; import com.stumeet.server.common.response.ErrorCode; import com.stumeet.server.common.model.ApiResponse; @@ -76,6 +77,17 @@ protected ResponseEntity handleMethodArgumentTypeMismatchException( .body(response); } + @ExceptionHandler(BadRequestException.class) + protected ResponseEntity handleCustomBadRequestException(final BadRequestException e) { + log.warn(ERROR_LOG_MESSAGE, e.getClass().getSimpleName(), e.getMessage()); + + String message = String.format("%s %s", e.getErrorCode().getMessage(), e.getMessage()); + ApiResponse response = ApiResponse.fail(e.getErrorCode().getHttpStatusCode(), message); + + return ResponseEntity.badRequest() + .body(response); + } + @ExceptionHandler({ HttpMessageNotReadableException.class, InvalidFormatException.class, diff --git a/src/main/java/com/stumeet/server/study/domain/exception/InvalidRepetitionDatesException.java b/src/main/java/com/stumeet/server/study/domain/exception/InvalidRepetitionDatesException.java index a9714a90..26f57a69 100644 --- a/src/main/java/com/stumeet/server/study/domain/exception/InvalidRepetitionDatesException.java +++ b/src/main/java/com/stumeet/server/study/domain/exception/InvalidRepetitionDatesException.java @@ -5,6 +5,6 @@ public class InvalidRepetitionDatesException extends BadRequestException { public InvalidRepetitionDatesException(String repetitionType) { - super("유효하지 않은 반복일 값 입니다. 반복유형: " + repetitionType, ErrorCode.METHOD_ARGUMENT_NOT_VALID_EXCEPTION); + super("유효하지 않은 반복일 값 입니다. 반복유형: " + repetitionType, ErrorCode.VALIDATION_REQUEST_EXCEPTION); } } From f06d52378cf0341febdfcc756847852da5ccce09 Mon Sep 17 00:00:00 2001 From: Lee ChanMi Date: Mon, 8 Apr 2024 10:06:07 +0900 Subject: [PATCH 30/35] =?UTF-8?q?:white=5Fcheck=5Fmark:=20[STMT-62]=20?= =?UTF-8?q?=EC=8A=A4=ED=84=B0=EB=94=94=20=EC=83=9D=EC=84=B1=20=ED=85=8C?= =?UTF-8?q?=EC=8A=A4=ED=8A=B8=20=EC=88=98=EC=A0=95:=20POST=20=EB=A9=94?= =?UTF-8?q?=EC=84=9C=EB=93=9C=20=EC=A7=80=EC=A0=95=20=EC=BD=94=EB=93=9C=20?= =?UTF-8?q?=EC=82=AD=EC=A0=9C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../adapter/in/web/StudyCreateApiTest.java | 21 ------------------- 1 file changed, 21 deletions(-) diff --git a/src/test/java/com/stumeet/server/study/adapter/in/web/StudyCreateApiTest.java b/src/test/java/com/stumeet/server/study/adapter/in/web/StudyCreateApiTest.java index 2290b5b3..4e9967cb 100644 --- a/src/test/java/com/stumeet/server/study/adapter/in/web/StudyCreateApiTest.java +++ b/src/test/java/com/stumeet/server/study/adapter/in/web/StudyCreateApiTest.java @@ -14,7 +14,6 @@ import org.junit.jupiter.api.Test; import org.springframework.http.MediaType; import org.springframework.mock.web.MockMultipartFile; -import org.springframework.test.web.servlet.request.RequestPostProcessor; import com.stumeet.server.common.auth.model.AuthenticationHeader; import com.stumeet.server.helper.WithMockMember; @@ -37,13 +36,8 @@ class CreateStudy { void successTest() throws Exception { StudyCreateCommand request = StudyStub.getStudyCreateCommand(); - RequestPostProcessor postMethod = http -> { - http.setMethod("POST"); - return http; - }; mockMvc.perform(multipart(path) .file((MockMultipartFile) request.image()) - .with(postMethod) .header(AuthenticationHeader.ACCESS_TOKEN.getName(), TokenStub.getMockAccessToken()) .queryParam("studyFieldId", String.valueOf(request.studyFieldId())) .queryParam("name", request.name()) @@ -121,12 +115,7 @@ void successTest() throws Exception { void successWithoutImageFile() throws Exception { StudyCreateCommand request = StudyStub.getStudyCreateCommand(); - RequestPostProcessor postMethod = http -> { - http.setMethod("POST"); - return http; - }; mockMvc.perform(multipart(path) - .with(postMethod) .header(AuthenticationHeader.ACCESS_TOKEN.getName(), TokenStub.getMockAccessToken()) .queryParam("studyFieldId", String.valueOf(request.studyFieldId())) .queryParam("name", request.name()) @@ -151,13 +140,8 @@ void failWithNotExistStudyFieldId() throws Exception { StudyCreateCommand request = StudyStub.getStudyCreateCommand(); int invalidStudyFieldId = 0; - RequestPostProcessor postMethod = http -> { - http.setMethod("POST"); - return http; - }; mockMvc.perform(multipart(path) .file((MockMultipartFile) request.image()) - .with(postMethod) .header(AuthenticationHeader.ACCESS_TOKEN.getName(), TokenStub.getMockAccessToken()) .queryParam("studyFieldId", String.valueOf(invalidStudyFieldId)) .queryParam("name", request.name()) @@ -190,13 +174,8 @@ void failWithNotExistStudyFieldId() throws Exception { void failWithInvalidStudyMeetingSchedule() throws Exception { StudyCreateCommand request = StudyStub.getStudyCreateCommand(); - RequestPostProcessor postMethod = http -> { - http.setMethod("POST"); - return http; - }; mockMvc.perform(multipart(path) .file((MockMultipartFile) request.image()) - .with(postMethod) .header(AuthenticationHeader.ACCESS_TOKEN.getName(), TokenStub.getMockAccessToken()) .queryParam("studyFieldId", String.valueOf(request.studyFieldId())) .queryParam("name", request.name()) From 9f53c07705a0afedf16fe3415aa247b644e54ec9 Mon Sep 17 00:00:00 2001 From: Lee ChanMi Date: Mon, 8 Apr 2024 10:06:34 +0900 Subject: [PATCH 31/35] =?UTF-8?q?:white=5Fcheck=5Fmark:=20[STMT-62]=20?= =?UTF-8?q?=EC=8A=A4=ED=84=B0=EB=94=94=20=EC=83=9D=EC=84=B1=20=ED=85=8C?= =?UTF-8?q?=EC=8A=A4=ED=8A=B8=20=EC=88=98=EC=A0=95:=20=EC=9D=91=EB=8B=B5?= =?UTF-8?q?=20=EB=82=B4=EC=9A=A9=20=EC=82=AD=EC=A0=9C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../adapter/in/web/StudyCreateApiTest.java | 20 +------------------ 1 file changed, 1 insertion(+), 19 deletions(-) diff --git a/src/test/java/com/stumeet/server/study/adapter/in/web/StudyCreateApiTest.java b/src/test/java/com/stumeet/server/study/adapter/in/web/StudyCreateApiTest.java index 4e9967cb..977d4e11 100644 --- a/src/test/java/com/stumeet/server/study/adapter/in/web/StudyCreateApiTest.java +++ b/src/test/java/com/stumeet/server/study/adapter/in/web/StudyCreateApiTest.java @@ -87,25 +87,7 @@ void successTest() throws Exception { ), responseFields( fieldWithPath("code").description("응답 상태"), - fieldWithPath("message").description("응답 메시지"), - fieldWithPath("data.id").description("스터디 ID"), - fieldWithPath("data.field").description("분야"), - fieldWithPath("data.name").description("스터디 이름"), - fieldWithPath("data.tags").description("태그 리스트"), - fieldWithPath("data.intro").description("소개"), - fieldWithPath("data.region").description("활동 지역"), - fieldWithPath("data.rule").description("규칙"), - fieldWithPath("data.image").description("이미지 URL"), - fieldWithPath("data.headcount").description("참여 인원 수"), - fieldWithPath("data.startDate").description("시작일"), - fieldWithPath("data.endDate").description("종료일"), - fieldWithPath("data.meetingTime").description("정기모임 시간"), - fieldWithPath("data.meetingRepetitionType") - .description("정기모임 반복 유형 / `매일`, `매주`, `매달`"), - fieldWithPath("data.meetingRepetitionDates") - .description("정기모임 반복일 / 매주: 요일, 매달: 날짜"), - fieldWithPath("data.isFinished").description("종료 여부"), - fieldWithPath("data.isDeleted").description("삭제 여부") + fieldWithPath("message").description("응답 메시지") ))); } From ce93769bcd48ccef3bc86cd35cd26446971c349b Mon Sep 17 00:00:00 2001 From: Lee ChanMi Date: Mon, 8 Apr 2024 10:32:51 +0900 Subject: [PATCH 32/35] =?UTF-8?q?:white=5Fcheck=5Fmark:=20[STMT-62]=20?= =?UTF-8?q?=EC=A0=95=EA=B8=B0=EC=9D=BC=EC=A0=95=20=ED=85=8C=EC=8A=A4?= =?UTF-8?q?=ED=8A=B8=20=EC=88=98=EC=A0=95:=20=EC=A0=95=EA=B8=B0=EC=9D=BC?= =?UTF-8?q?=EC=A0=95=20=EB=B0=98=EB=B3=B5=20=ED=85=8C=EC=8A=A4=ED=8A=B8?= =?UTF-8?q?=EB=A1=9C=20=EB=B3=80=EA=B2=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../study/domain/StudyMeetingSchedule.java | 2 +- .../stumeet/server/stub/RepetitionStub.java | 30 +++++++++++ ...gScheduleTest.java => RepetitionTest.java} | 52 +++++++------------ 3 files changed, 50 insertions(+), 34 deletions(-) create mode 100644 src/test/java/com/stumeet/server/stub/RepetitionStub.java rename src/test/java/com/stumeet/server/study/domain/{StudyMeetingScheduleTest.java => RepetitionTest.java} (61%) diff --git a/src/main/java/com/stumeet/server/study/domain/StudyMeetingSchedule.java b/src/main/java/com/stumeet/server/study/domain/StudyMeetingSchedule.java index 19592dc0..a5a29f54 100644 --- a/src/main/java/com/stumeet/server/study/domain/StudyMeetingSchedule.java +++ b/src/main/java/com/stumeet/server/study/domain/StudyMeetingSchedule.java @@ -26,7 +26,7 @@ public static class Repetition { private final List dates; @Builder - public Repetition(RepetitionType type, List dates) { + private Repetition(RepetitionType type, List dates) { validateRepetition(type, dates); this.type = type; this.dates = type.equals(RepetitionType.DAILY) ? null : dates; diff --git a/src/test/java/com/stumeet/server/stub/RepetitionStub.java b/src/test/java/com/stumeet/server/stub/RepetitionStub.java new file mode 100644 index 00000000..71ba00e4 --- /dev/null +++ b/src/test/java/com/stumeet/server/stub/RepetitionStub.java @@ -0,0 +1,30 @@ +package com.stumeet.server.stub; + +import java.util.List; + +import com.stumeet.server.study.domain.RepetitionType; +import com.stumeet.server.study.domain.StudyMeetingSchedule; + +public class RepetitionStub { + + public static StudyMeetingSchedule.Repetition getDailyRepetition() { + return StudyMeetingSchedule.Repetition.builder() + .type(RepetitionType.DAILY) + .dates(null) + .build(); + } + + public static StudyMeetingSchedule.Repetition getWeeklyRepetition() { + return StudyMeetingSchedule.Repetition.builder() + .type(RepetitionType.WEEKLY) + .dates(List.of("수", "금")) + .build(); + } + + public static StudyMeetingSchedule.Repetition getMonthlyRepetition() { + return StudyMeetingSchedule.Repetition.builder() + .type(RepetitionType.MONTHLY) + .dates(List.of("10", "20", "30")) + .build(); + } +} diff --git a/src/test/java/com/stumeet/server/study/domain/StudyMeetingScheduleTest.java b/src/test/java/com/stumeet/server/study/domain/RepetitionTest.java similarity index 61% rename from src/test/java/com/stumeet/server/study/domain/StudyMeetingScheduleTest.java rename to src/test/java/com/stumeet/server/study/domain/RepetitionTest.java index 431bc0ba..be1b1fc1 100644 --- a/src/test/java/com/stumeet/server/study/domain/StudyMeetingScheduleTest.java +++ b/src/test/java/com/stumeet/server/study/domain/RepetitionTest.java @@ -1,21 +1,18 @@ package com.stumeet.server.study.domain; import static org.assertj.core.api.Assertions.*; -import static org.assertj.core.api.Assertions.assertThatCode; -import java.time.LocalTime; import java.util.List; import org.junit.jupiter.api.DisplayName; import org.junit.jupiter.api.Nested; import org.junit.jupiter.api.Test; +import com.stumeet.server.stub.RepetitionStub; import com.stumeet.server.study.domain.exception.InvalidRepetitionDatesException; import com.stumeet.server.template.UnitTest; -class StudyMeetingScheduleTest extends UnitTest { - - private final LocalTime meetingTime = LocalTime.of(18, 30); +public class RepetitionTest extends UnitTest { @Nested @DisplayName("[단위 테스트] 스터디 일정 생성") @@ -24,58 +21,47 @@ class create { @Test @DisplayName("[성공] 반복 유형이 DAILY일 때, 인수 dates에 null을 전달 받았을 경우 생성에 성공한다.") void weeklyTypeNullDatesSuccessTest() { - StudyMeetingSchedule.Repetition dailyRepetition = StudyMeetingSchedule.Repetition.builder() + assertThatCode(() -> StudyMeetingSchedule.Repetition.builder() .type(RepetitionType.DAILY) .dates(null) - .build(); - - assertThatCode(() -> StudyMeetingSchedule.builder() - .time(meetingTime) - .repetition(dailyRepetition) .build()) .doesNotThrowAnyException(); + + assertThat(StudyMeetingSchedule.Repetition.builder() + .type(RepetitionType.DAILY) + .dates(null) + .build()) + .usingRecursiveComparison() + .isEqualTo(RepetitionStub.getDailyRepetition()); } @Test @DisplayName("[성공] 반복 유형이 DAILY일 때, 인수 dates에 null이 아닌 값을 전달 받았을 경우 생성에 성공한다.") void weeklyTypeInvalidDatesSuccessTest() { - StudyMeetingSchedule.Repetition dailyRepetitionWithNonNullDates = StudyMeetingSchedule.Repetition.builder() + assertThat(StudyMeetingSchedule.Repetition.builder() .type(RepetitionType.DAILY) .dates(List.of("월", "화", "수", "목", "금", "토", "일")) - .build(); - - assertThat(StudyMeetingSchedule.builder() - .time(meetingTime) - .repetition(dailyRepetitionWithNonNullDates) .build() - .getRepetitionDates()) + .getDates()) .isNull(); } @Test @DisplayName("[성공] 반복 유형이 DAILY가 아닐 때, 유효한 값을 전달 받았을 경우 생성에 성공한다.") void otherTypesSuccessTest() { - StudyMeetingSchedule.Repetition weeklyRepetition = StudyMeetingSchedule.Repetition.builder() + assertThat(StudyMeetingSchedule.Repetition.builder() .type(RepetitionType.WEEKLY) .dates(List.of("수", "금")) - .build(); - - assertThatCode(() -> StudyMeetingSchedule.builder() - .time(meetingTime) - .repetition(weeklyRepetition) .build()) - .doesNotThrowAnyException(); + .usingRecursiveComparison() + .isEqualTo(RepetitionStub.getWeeklyRepetition()); - StudyMeetingSchedule.Repetition monthlyRepetition = StudyMeetingSchedule.Repetition.builder() + assertThat(StudyMeetingSchedule.Repetition.builder() .type(RepetitionType.MONTHLY) .dates(List.of("10", "20", "30")) - .build(); - - assertThatCode(() -> StudyMeetingSchedule.builder() - .time(meetingTime) - .repetition(monthlyRepetition) .build()) - .doesNotThrowAnyException(); + .usingRecursiveComparison() + .isEqualTo(RepetitionStub.getMonthlyRepetition()); } @Test @@ -94,4 +80,4 @@ void invalidDatesFailTest() { .isInstanceOf(InvalidRepetitionDatesException.class); } } -} \ No newline at end of file +} From 6b9db22963f6dc859b649b99405d69f844f898b8 Mon Sep 17 00:00:00 2001 From: Lee ChanMi Date: Mon, 8 Apr 2024 10:51:03 +0900 Subject: [PATCH 33/35] =?UTF-8?q?:construction:=20[STMT-62]=20StudyFieldPe?= =?UTF-8?q?rsistenceAdapter=20=ED=95=84=EC=88=98=20=EC=83=9D=EC=84=B1?= =?UTF-8?q?=EC=9E=90=EC=97=90=20=EC=A0=91=EA=B7=BC=20=EC=A0=9C=ED=95=9C?= =?UTF-8?q?=EC=9E=90=20=EC=84=A4=EC=A0=95=20=EC=82=AD=EC=A0=9C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../adapter/out/persistance/StudyFieldPersistenceAdapter.java | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/main/java/com/stumeet/server/study/adapter/out/persistance/StudyFieldPersistenceAdapter.java b/src/main/java/com/stumeet/server/study/adapter/out/persistance/StudyFieldPersistenceAdapter.java index 25fcc024..53509ba4 100644 --- a/src/main/java/com/stumeet/server/study/adapter/out/persistance/StudyFieldPersistenceAdapter.java +++ b/src/main/java/com/stumeet/server/study/adapter/out/persistance/StudyFieldPersistenceAdapter.java @@ -7,11 +7,10 @@ import com.stumeet.server.study.domain.StudyField; import com.stumeet.server.study.domain.exception.StudyFieldNotExistsException; -import lombok.AccessLevel; import lombok.RequiredArgsConstructor; @PersistenceAdapter -@RequiredArgsConstructor(access = AccessLevel.PRIVATE) +@RequiredArgsConstructor public class StudyFieldPersistenceAdapter implements StudyFieldQueryPort { private final JpaStudyFieldRepository studyFieldRepository; From 99d9af8ed08a6eaadb33c848801fc925c6c79c6f Mon Sep 17 00:00:00 2001 From: Lee ChanMi Date: Mon, 8 Apr 2024 10:51:46 +0900 Subject: [PATCH 34/35] =?UTF-8?q?:construction:=20[STMT-62]=20StudyDomainC?= =?UTF-8?q?reateService=20=EA=B5=AC=ED=98=84=EC=9C=BC=EB=A1=9C=20Study=20D?= =?UTF-8?q?omain=20=EC=83=9D=EC=84=B1=20=EB=A1=9C=EC=A7=81=20=EB=B6=84?= =?UTF-8?q?=EB=A6=AC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../port/in/StudyDomainCreateUseCase.java | 8 +++++ .../service/StudyCreateService.java | 18 ++-------- .../service/StudyDomainCreateService.java | 34 +++++++++++++++++++ 3 files changed, 45 insertions(+), 15 deletions(-) create mode 100644 src/main/java/com/stumeet/server/study/application/port/in/StudyDomainCreateUseCase.java create mode 100644 src/main/java/com/stumeet/server/study/application/service/StudyDomainCreateService.java diff --git a/src/main/java/com/stumeet/server/study/application/port/in/StudyDomainCreateUseCase.java b/src/main/java/com/stumeet/server/study/application/port/in/StudyDomainCreateUseCase.java new file mode 100644 index 00000000..03983549 --- /dev/null +++ b/src/main/java/com/stumeet/server/study/application/port/in/StudyDomainCreateUseCase.java @@ -0,0 +1,8 @@ +package com.stumeet.server.study.application.port.in; + +import com.stumeet.server.study.domain.StudyDomain; + +public interface StudyDomainCreateUseCase { + + StudyDomain create(StudyDomain studyDomain); +} diff --git a/src/main/java/com/stumeet/server/study/application/service/StudyCreateService.java b/src/main/java/com/stumeet/server/study/application/service/StudyCreateService.java index d60000d6..77aef020 100644 --- a/src/main/java/com/stumeet/server/study/application/service/StudyCreateService.java +++ b/src/main/java/com/stumeet/server/study/application/service/StudyCreateService.java @@ -6,13 +6,12 @@ import com.stumeet.server.file.application.port.in.FileUploadUseCase; import com.stumeet.server.member.domain.Member; import com.stumeet.server.study.application.port.in.StudyCreateUseCase; +import com.stumeet.server.study.application.port.in.StudyDomainCreateUseCase; import com.stumeet.server.study.application.port.in.command.StudyCreateCommand; import com.stumeet.server.study.application.port.in.mapper.StudyDomainUseCaseMapper; import com.stumeet.server.study.application.port.in.mapper.StudyUseCaseMapper; import com.stumeet.server.study.application.port.out.StudyCommandPort; -import com.stumeet.server.study.application.port.out.StudyDomainCommandPort; import com.stumeet.server.study.application.port.out.StudyFieldQueryPort; -import com.stumeet.server.study.application.port.out.StudyTagCommandPort; import com.stumeet.server.study.domain.Study; import com.stumeet.server.study.domain.StudyDomain; import com.stumeet.server.studymember.application.port.in.StudyMemberJoinUseCase; @@ -26,11 +25,10 @@ public class StudyCreateService implements StudyCreateUseCase { private final FileUploadUseCase fileUploadUseCase; private final StudyMemberJoinUseCase memberJoinUseCase; + private final StudyDomainCreateUseCase studyDomainCreateUseCase; private final StudyCommandPort studyCommandPort; private final StudyFieldQueryPort studyFieldQueryPort; - private final StudyDomainCommandPort studyDomainCommandPort; - private final StudyTagCommandPort studyTagCommandPort; private final StudyUseCaseMapper studyUseCaseMapper; private final StudyDomainUseCaseMapper studyDomainUseCaseMapper; @@ -39,7 +37,7 @@ public class StudyCreateService implements StudyCreateUseCase { public Long create(StudyCreateCommand command, Member member) { studyFieldQueryPort.checkById(command.studyFieldId()); - StudyDomain studyDomainCreated = createStudyDomain(studyDomainUseCaseMapper.toDomain(command)); + StudyDomain studyDomainCreated = studyDomainCreateUseCase.create(studyDomainUseCaseMapper.toDomain(command)); String mainImageUrl = fileUploadUseCase.uploadStudyMainImage(command.image()).url(); Study study = Study.create(command, studyDomainCreated, mainImageUrl); @@ -48,14 +46,4 @@ public Long create(StudyCreateCommand command, Member member) { memberJoinUseCase.join(studyUseCaseMapper.toAdminStudyMemberJoinCommand(member.getId(), studyCreated.getId())); return studyCreated.getId(); } - - private StudyDomain createStudyDomain(StudyDomain studyDomain) { - StudyDomain created = studyDomainCommandPort.save(studyDomain); - - if (created.isStudyTagNotEmpty()) { - studyTagCommandPort.saveAll(created.getStudyTags(), created.getId()); - } - - return created; - } } diff --git a/src/main/java/com/stumeet/server/study/application/service/StudyDomainCreateService.java b/src/main/java/com/stumeet/server/study/application/service/StudyDomainCreateService.java new file mode 100644 index 00000000..3bea4f1f --- /dev/null +++ b/src/main/java/com/stumeet/server/study/application/service/StudyDomainCreateService.java @@ -0,0 +1,34 @@ +package com.stumeet.server.study.application.service; + +import java.util.List; + +import com.stumeet.server.common.annotation.UseCase; +import com.stumeet.server.study.application.port.in.StudyDomainCreateUseCase; +import com.stumeet.server.study.application.port.out.StudyDomainCommandPort; +import com.stumeet.server.study.application.port.out.StudyTagCommandPort; +import com.stumeet.server.study.domain.StudyDomain; +import com.stumeet.server.study.domain.StudyTag; + +import lombok.RequiredArgsConstructor; + +@UseCase +@RequiredArgsConstructor +public class StudyDomainCreateService implements StudyDomainCreateUseCase { + + private final StudyDomainCommandPort studyDomainCommandPort; + private final StudyTagCommandPort studyTagCommandPort; + + @Override + public StudyDomain create(StudyDomain studyDomain) { + StudyDomain created = studyDomainCommandPort.save(studyDomain); + if (created.isStudyTagNotEmpty()) { + createStudyTags(created.getStudyTags(), created.getId()); + } + + return created; + } + + private List createStudyTags(List studyTags, Long studyDomainId) { + return studyTagCommandPort.saveAll(studyTags, studyDomainId); + } +} From 2f299f8a1f2c15b837285a288c088755c196f816 Mon Sep 17 00:00:00 2001 From: Lee ChanMi Date: Mon, 8 Apr 2024 11:08:10 +0900 Subject: [PATCH 35/35] =?UTF-8?q?:lipstick:=20[STMT-62]=20=EB=B3=80?= =?UTF-8?q?=EC=88=98=EB=AA=85=20=EB=B3=80=EA=B2=BD=20=EB=B0=8F=20=EB=B6=88?= =?UTF-8?q?=ED=95=84=EC=9A=94=ED=95=9C=20=EC=BD=94=EB=93=9C=20=EC=A0=9C?= =?UTF-8?q?=EA=B1=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../study/application/service/StudyCreateService.java | 6 +++--- .../server/study/application/service/StudyQueryService.java | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/main/java/com/stumeet/server/study/application/service/StudyCreateService.java b/src/main/java/com/stumeet/server/study/application/service/StudyCreateService.java index 77aef020..f6569ed7 100644 --- a/src/main/java/com/stumeet/server/study/application/service/StudyCreateService.java +++ b/src/main/java/com/stumeet/server/study/application/service/StudyCreateService.java @@ -41,9 +41,9 @@ public Long create(StudyCreateCommand command, Member member) { String mainImageUrl = fileUploadUseCase.uploadStudyMainImage(command.image()).url(); Study study = Study.create(command, studyDomainCreated, mainImageUrl); - Study studyCreated = studyCommandPort.save(study); + Study createdStudy = studyCommandPort.save(study); - memberJoinUseCase.join(studyUseCaseMapper.toAdminStudyMemberJoinCommand(member.getId(), studyCreated.getId())); - return studyCreated.getId(); + memberJoinUseCase.join(studyUseCaseMapper.toAdminStudyMemberJoinCommand(member.getId(), createdStudy.getId())); + return createdStudy.getId(); } } diff --git a/src/main/java/com/stumeet/server/study/application/service/StudyQueryService.java b/src/main/java/com/stumeet/server/study/application/service/StudyQueryService.java index 273f1007..b29203de 100644 --- a/src/main/java/com/stumeet/server/study/application/service/StudyQueryService.java +++ b/src/main/java/com/stumeet/server/study/application/service/StudyQueryService.java @@ -20,7 +20,7 @@ public class StudyQueryService implements StudyQueryUseCase { private final StudyUseCaseMapper studyUseCaseMapper; @Override - public StudyDetailResponse getStudyDetailById(java.lang.Long id) { + public StudyDetailResponse getStudyDetailById(Long id) { Study study = studyQueryPort.getById(id); return studyUseCaseMapper.toStudyDetailResponse(study); }