Skip to content

Commit

Permalink
✨[STMT-179] 활동 생성 request body 필드 필수 요청 값 수정 및 검증 로직 추가 (#140)
Browse files Browse the repository at this point in the history
* 🗃️ [STMT-179] activity 테이블에 활동 기간 nullable, link 컬럼 추가

* ✨ [STMT-179] request body의 필드 유효성 검증 방침 변경: null 허용

* ✨ [STMT-179] 활동을 상속받은 각 활동 유형마다 필수 입력값 검증 로직 추가

* ✨ [STMT-179] 활동 생성시 멤버 관리자 여부 대신 스터디 멤버인지 검증

* ✅ [STMT-179] 활동 생성 기존 테스트 수정 및 추가 예외 사항 테스트 케이스 작성

* 📝 [STMT-179] 활동 생성 API 명세서 추가 작성
  • Loading branch information
05AM authored Jul 15, 2024
1 parent b15b750 commit 55f3a26
Show file tree
Hide file tree
Showing 18 changed files with 351 additions and 90 deletions.
16 changes: 14 additions & 2 deletions src/docs/asciidoc/index.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -473,14 +473,26 @@ include::{snippets}/create-activity/fail/not-exists-category/response-fields.ado

===== 응답 실패 (403)
.스터디의 관리자가 아닌 경우
include::{snippets}/create-activity/fail/not-admin/response-body.adoc[]
include::{snippets}/create-activity/fail/not-admin/response-fields.adoc[]
include::{snippets}/create-activity/fail/not-study-member/response-body.adoc[]
include::{snippets}/create-activity/fail/not-study-member/response-fields.adoc[]

====== 응답 실패 (404)
.존재하지 않는 스터디 ID를 요청한 경우
include::{snippets}/create-activity/fail/not-exists-study/response-body.adoc[]
include::{snippets}/create-activity/fail/not-exists-study/response-fields.adoc[]

.모임 활동 생성 시 장소 값이 null인 경우
include::{snippets}/create-activity/fail/location-null-for-meet/response-body.adoc[]
include::{snippets}/create-activity/fail/location-null-for-meet/response-fields.adoc[]

.모임, 과제 활동 생성 시 활동 기간이 null인 경우
include::{snippets}/create-activity/fail/period-null/response-body.adoc[]
include::{snippets}/create-activity/fail/period-null/response-fields.adoc[]

.모임, 과제 활동 생성 시 활동 기간이 유효하지 않은 경우
include::{snippets}/create-activity/fail/period-invalid/response-body.adoc[]
include::{snippets}/create-activity/fail/period-invalid/response-fields.adoc[]


=== 스터디 활동 상세 목록 조회

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -47,15 +47,15 @@ public class ActivityJpaEntity extends BaseTimeEntity {
@Comment("공지 여부")
private boolean isNotice;

@Column(name = "start_date", nullable = false)
@Column(name = "start_date")
@Comment("활동 시작일")
private LocalDateTime startDate;

@Column(name = "end_date", nullable = false)
@Column(name = "end_date")
@Comment("활동 종료일")
private LocalDateTime endDate;

@Column(name = "location", nullable = false)
@Column(name = "location")
@Comment("활동 장소")
private String location;
}
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
package com.stumeet.server.activity.application.port.in.command;

import jakarta.annotation.Nullable;
import jakarta.validation.constraints.NotBlank;
import jakarta.validation.constraints.NotNull;
import jakarta.validation.constraints.Size;
Expand All @@ -9,6 +10,8 @@
import java.time.LocalDateTime;
import java.util.List;

import com.stumeet.server.common.annotation.validator.NullOrNotBlank;

@Builder
public record ActivityCreateCommand(
@NotBlank(message = "활동 카테고리를 입력해주세요")
Expand All @@ -28,16 +31,21 @@ public record ActivityCreateCommand(

boolean isNotice,

@DateTimeFormat(pattern = "yyyy-MM-dd''HH:mm:ss")
@Nullable
@DateTimeFormat(pattern = "yyyy-MM-dd'T'HH:mm:ss")
LocalDateTime startDate,

@Nullable
@DateTimeFormat(pattern = "yyyy-MM-dd'T'HH:mm:ss")
LocalDateTime endDate,

@NullOrNotBlank
String location,

@NullOrNotBlank
String link,

@NotNull(message = "참여 멤버 리스트를 전달해주세요")
@Size(min = 1, message = "참여 멤버는 1명 이상이어야 합니다")
List<Long> participants

) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -35,10 +35,11 @@ public ActivityCreateSource toSource(Long studyId, ActivityCreateCommand command
.category(ActivityCategory.getByName(command.category()))
.title(command.title())
.content(command.content())
.isNotice(command.isNotice())
.location(command.location())
.link(command.link())
.startDate(command.startDate())
.endDate(command.endDate())
.location(command.location())
.isNotice(command.isNotice())
.createdAt(LocalDateTime.now())
.build();
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ public class ActivityCreateService implements ActivityCreateUseCase {
@Override
public void create(Long studyId, ActivityCreateCommand command, Long memberId) {
studyValidationUseCase.checkById(studyId);
studyMemberValidationUseCase.checkAdmin(studyId, memberId);
studyMemberValidationUseCase.checkStudyJoinMember(studyId, memberId);

ActivityCreateSource activitySource = activityUseCaseMapper.toSource(studyId, command, memberId);
Activity activity = activitySource.category().create(activitySource);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,10 +13,11 @@ public record ActivityCreateSource(
ActivityCategory category,
String title,
String content,
boolean isNotice,
LocalDateTime startDate,
LocalDateTime endDate,
String location,
String link,
boolean isNotice,
LocalDateTime createdAt
) {
@Builder
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@

import java.time.LocalDateTime;

import org.springframework.cglib.core.Local;

@AllArgsConstructor(access = AccessLevel.PROTECTED)
@Getter
public abstract class Activity {
Expand All @@ -22,13 +24,15 @@ public abstract class Activity {

private String content;

private boolean isNotice;
private String link;

private String location;

private LocalDateTime startDate;

private LocalDateTime endDate;

private String location;
private boolean isNotice;

private LocalDateTime createdAt;

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

import com.stumeet.server.activity.application.service.model.ActivityCreateSource;
import com.stumeet.server.activity.domain.exception.NotExistsActivityCategoryException;

import lombok.Getter;
import lombok.RequiredArgsConstructor;

Expand All @@ -12,80 +13,83 @@
public enum ActivityCategory {
DEFAULT(DefaultStatus.NONE) {
@Override
public Activity create(ActivityCreateSource command) {
public Activity create(ActivityCreateSource source) {
return Default.builder()
.id(command.id())
.study(ActivityLinkedStudy.builder().id(command.studyId()).build())
.id(source.id())
.study(ActivityLinkedStudy.builder().id(source.studyId()).build())
.author(ActivityMember.builder()
.id(command.author().id())
.name(command.author().name())
.image(command.author().image())
.id(source.author().id())
.name(source.author().name())
.image(source.author().image())
.build()
)
.category(command.category())
.title(command.title())
.content(command.content())
.isNotice(command.isNotice())
.startDate(command.startDate())
.endDate(command.endDate())
.createdAt(command.createdAt())
.category(source.category())
.title(source.title())
.content(source.content())
.link(source.link())
.isNotice(source.isNotice())
.createdAt(source.createdAt())
.build();
}
},

MEET(MeetStatus.MEET_NOT_STARTED) {
@Override
public Activity create(ActivityCreateSource command) {
public Activity create(ActivityCreateSource source) {
return Meet.builder()
.id(command.id())
.study(ActivityLinkedStudy.builder().id(command.studyId()).build())
.id(source.id())
.study(ActivityLinkedStudy.builder().id(source.studyId()).build())
.author(ActivityMember.builder()
.id(command.author().id())
.name(command.author().name())
.image(command.author().image())
.id(source.author().id())
.name(source.author().name())
.image(source.author().image())
.build()
)
.category(command.category())
.title(command.title())
.content(command.content())
.isNotice(command.isNotice())
.startDate(command.startDate())
.endDate(command.endDate())
.location(command.location())
.createdAt(command.createdAt())
.category(source.category())
.title(source.title())
.content(source.content())
.location(source.location())
.link(source.link())
.startDate(source.startDate())
.endDate(source.endDate())
.isNotice(source.isNotice())
.createdAt(source.createdAt())
.build();
}
},
ASSIGNMENT(AssignmentStatus.ASSIGNMENT_NOT_STARTED) {
@Override
public Activity create(ActivityCreateSource command) {
public Activity create(ActivityCreateSource source) {
return Assignment.builder()
.id(command.id())
.study(ActivityLinkedStudy.builder().id(command.studyId()).build())
.id(source.id())
.study(ActivityLinkedStudy.builder().id(source.studyId()).build())
.author(ActivityMember.builder()
.id(command.author().id())
.name(command.author().name())
.image(command.author().image())
.id(source.author().id())
.name(source.author().name())
.image(source.author().image())
.build()
)
.category(command.category())
.title(command.title())
.content(command.content())
.isNotice(command.isNotice())
.startDate(command.startDate())
.endDate(command.endDate())
.createdAt(command.createdAt())
.category(source.category())
.title(source.title())
.content(source.content())
.link(source.content())
.startDate(source.startDate())
.endDate(source.endDate())
.isNotice(source.isNotice())
.createdAt(source.createdAt())
.build();
}
};

private final ActivityStatus defaultStatus;

public static ActivityCategory getByName(String category) {
return Arrays.stream(ActivityCategory.values())
.filter(c -> c.name().equalsIgnoreCase(category))
.findAny()
.orElseThrow(() -> new NotExistsActivityCategoryException(category));
}
public abstract Activity create(ActivityCreateSource command);

public abstract Activity create(ActivityCreateSource source);

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
package com.stumeet.server.activity.domain.model;

import java.time.LocalDateTime;

import com.stumeet.server.common.exception.model.BadRequestException;
import com.stumeet.server.common.response.ErrorCode;

import lombok.Builder;
import lombok.Getter;

@Getter
public class ActivityPeriod {

private LocalDateTime startDate;

private LocalDateTime endDate;

@Builder
private ActivityPeriod(LocalDateTime startDate, LocalDateTime endDate) {
validate(startDate, endDate);

this.startDate = startDate;
this.endDate = endDate;
}

private void validate(LocalDateTime startDate, LocalDateTime endDate) {
validateNonNull(startDate, endDate);
validatePeriod(startDate, endDate);
}

private void validateNonNull(LocalDateTime startDate, LocalDateTime endDate) {
if (startDate == null || endDate == null) {
throw new BadRequestException(ErrorCode.ACTIVITY_PERIOD_REQUIRED_EXCEPTION);
}
}

private void validatePeriod(LocalDateTime startDate, LocalDateTime endDate) {
if (startDate.isAfter(endDate)) {
throw new BadRequestException(ErrorCode.INVALID_PERIOD_EXCEPTION);
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,15 @@

public class Assignment extends Activity {

private ActivityPeriod period;

@Builder
protected Assignment(Long id, ActivityLinkedStudy study, ActivityMember author, ActivityCategory category, String title, String content, boolean isNotice, LocalDateTime startDate, LocalDateTime endDate, LocalDateTime createdAt) {
super(id, study, author, category, title, content, isNotice, startDate, endDate, null, createdAt);
protected Assignment(Long id, ActivityLinkedStudy study, ActivityMember author, ActivityCategory category, String title, String content, boolean isNotice, LocalDateTime startDate, LocalDateTime endDate, String link, LocalDateTime createdAt) {
super(id, study, author, category, title, content, link, null, startDate, endDate, isNotice, createdAt);

this.period = ActivityPeriod.builder()
.startDate(startDate)
.endDate(endDate)
.build();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
public class Default extends Activity {

@Builder
protected Default(Long id, ActivityLinkedStudy study, ActivityMember author, ActivityCategory category, String title, String content, boolean isNotice, LocalDateTime startDate, LocalDateTime endDate, String location, LocalDateTime createdAt) {
super(id, study, author, category, title, content, isNotice, startDate, endDate, location, createdAt);
protected Default(Long id, ActivityLinkedStudy study, ActivityMember author, ActivityCategory category, String title, String content, String link, boolean isNotice, LocalDateTime createdAt) {
super(id, study, author, category, title, content, link, null, null, null, isNotice, createdAt);
}
}
22 changes: 20 additions & 2 deletions src/main/java/com/stumeet/server/activity/domain/model/Meet.java
Original file line number Diff line number Diff line change
Expand Up @@ -5,11 +5,29 @@

import java.time.LocalDateTime;

import com.stumeet.server.common.exception.model.BadRequestException;
import com.stumeet.server.common.response.ErrorCode;

@Getter
public class Meet extends Activity {

private ActivityPeriod period;

@Builder
protected Meet(Long id, ActivityLinkedStudy study, ActivityMember author, ActivityCategory category, String title, String content, boolean isNotice, LocalDateTime startDate, LocalDateTime endDate, String location, LocalDateTime createdAt) {
super(id, study, author, category, title, content, isNotice, startDate, endDate, location, createdAt);
protected Meet(Long id, ActivityLinkedStudy study, ActivityMember author, ActivityCategory category, String title, String content, String location, String link, LocalDateTime startDate, LocalDateTime endDate, boolean isNotice, LocalDateTime createdAt) {
super(id, study, author, category, title, content, link, location, startDate, endDate, isNotice, createdAt);

validateLocationNonNull(location);

this.period = ActivityPeriod.builder()
.startDate(startDate)
.endDate(endDate)
.build();
}

private void validateLocationNonNull(String location) {
if (location == null) {
throw new BadRequestException(ErrorCode.LOCATION_REQUIRED_FOR_MEET_EXCEPTION);
}
}
}
Loading

0 comments on commit 55f3a26

Please sign in to comment.