diff --git a/build.gradle b/build.gradle index ea4402d..80325ee 100644 --- a/build.gradle +++ b/build.gradle @@ -27,6 +27,7 @@ dependencies { implementation 'org.springframework.boot:spring-boot-starter-data-jpa' implementation 'org.springframework.boot:spring-boot-starter-validation' implementation 'org.springframework.boot:spring-boot-starter-web' + implementation 'org.springframework.boot:spring-boot-starter-webflux' compileOnly 'org.projectlombok:lombok' runtimeOnly 'com.h2database:h2' annotationProcessor 'org.projectlombok:lombok' diff --git a/src/main/java/com/retrip/crew/application/in/CrewService.java b/src/main/java/com/retrip/crew/application/in/CrewService.java index 4cddfcf..661c355 100644 --- a/src/main/java/com/retrip/crew/application/in/CrewService.java +++ b/src/main/java/com/retrip/crew/application/in/CrewService.java @@ -14,9 +14,11 @@ @RequiredArgsConstructor public class CrewService implements CreateCrewUseCase { private final CrewRepository crewRepository; + @Override public CrewCreateResponse createCrew(CrewCreateRequest request) { - Crew crew = crewRepository.save(request.to()); + Crew crew = crewRepository.save(request.to(request.leader())); + return CrewCreateResponse.of(crew); } } diff --git a/src/main/java/com/retrip/crew/application/in/request/CrewCreateRequest.java b/src/main/java/com/retrip/crew/application/in/request/CrewCreateRequest.java index d840e89..c987d3d 100644 --- a/src/main/java/com/retrip/crew/application/in/request/CrewCreateRequest.java +++ b/src/main/java/com/retrip/crew/application/in/request/CrewCreateRequest.java @@ -3,12 +3,17 @@ import com.retrip.crew.domain.entity.Crew; import jakarta.validation.constraints.Size; +import java.util.UUID; + public record CrewCreateRequest( + UUID leader, @Size(min = 1, max = 30) - String title + String title, + @Size(min = 1, max = 500) + String description ){ - public Crew to() { - return Crew.create(this.title); + public Crew to(UUID leader) { + return Crew.create(this.title, this.description, leader); } } diff --git a/src/main/java/com/retrip/crew/application/in/response/CrewCreateResponse.java b/src/main/java/com/retrip/crew/application/in/response/CrewCreateResponse.java index b062770..b710eba 100644 --- a/src/main/java/com/retrip/crew/application/in/response/CrewCreateResponse.java +++ b/src/main/java/com/retrip/crew/application/in/response/CrewCreateResponse.java @@ -4,12 +4,18 @@ import java.util.UUID; -public record CrewCreateResponse ( - UUID id -){ - public static CrewCreateResponse of(Crew crew){ +public record CrewCreateResponse( + UUID id, + String title, + String description, + UUID leaderId +) { + public static CrewCreateResponse of(Crew crew) { return new CrewCreateResponse( - crew.getId() + crew.getId(), + crew.getTitle().getValue(), + crew.getDescription().getValue(), + crew.getLeader().getId() ); } } diff --git a/src/main/java/com/retrip/crew/domain/converter/CrewMemberRoleConverter.java b/src/main/java/com/retrip/crew/domain/converter/CrewMemberRoleConverter.java new file mode 100644 index 0000000..fd4ea2c --- /dev/null +++ b/src/main/java/com/retrip/crew/domain/converter/CrewMemberRoleConverter.java @@ -0,0 +1,24 @@ +package com.retrip.crew.domain.converter; + +import com.retrip.crew.domain.entity.CrewMemberRole; +import jakarta.persistence.AttributeConverter; +import jakarta.persistence.Converter; + +@Converter(autoApply = true) +public class CrewMemberRoleConverter implements AttributeConverter { + @Override + public String convertToDatabaseColumn(CrewMemberRole crewMemberRole) { + if(crewMemberRole == null){ + throw new NullPointerException("crewMemberRole을 DB 칼럼으로 변경하는 과정에서 null이 포함되었습니다."); + } + return crewMemberRole.getCode(); + } + + @Override + public CrewMemberRole convertToEntityAttribute(String dbData) { + if(dbData == null){ + throw new NullPointerException("CrewMember 테이블의 role 값이 null입니다."); + } + return CrewMemberRole.codeOf(dbData); + } +} diff --git a/src/main/java/com/retrip/crew/domain/entity/Announcement.java b/src/main/java/com/retrip/crew/domain/entity/Announcement.java new file mode 100644 index 0000000..ca4def9 --- /dev/null +++ b/src/main/java/com/retrip/crew/domain/entity/Announcement.java @@ -0,0 +1,35 @@ +package com.retrip.crew.domain.entity; + +import com.retrip.crew.domain.vo.AnnouncementContent; +import com.retrip.crew.domain.vo.AnnouncementTitle; +import com.retrip.crew.domain.vo.NotificationBoardContent; +import jakarta.persistence.*; +import lombok.AccessLevel; +import lombok.Getter; +import lombok.NoArgsConstructor; + +import java.util.UUID; + +@Entity +@NoArgsConstructor(access = AccessLevel.PROTECTED) +@Getter +public class Announcement extends BaseEntity { + @Id + @Column(columnDefinition = "varbinary(16)") + private UUID id; + + @Embedded + private AnnouncementTitle title; + + @Embedded + private AnnouncementContent content; + + @ManyToOne(fetch = FetchType.LAZY) + @JoinColumn( + name = "crew_id", + nullable = false, + columnDefinition = "varbinary(16)", + foreignKey = @ForeignKey(name = "fk_notification_board_to_crew") + ) + private Crew crew; +} diff --git a/src/main/java/com/retrip/crew/domain/entity/Announcements.java b/src/main/java/com/retrip/crew/domain/entity/Announcements.java new file mode 100644 index 0000000..9a85944 --- /dev/null +++ b/src/main/java/com/retrip/crew/domain/entity/Announcements.java @@ -0,0 +1,26 @@ +package com.retrip.crew.domain.entity; + +import jakarta.persistence.CascadeType; +import jakarta.persistence.Embeddable; +import jakarta.persistence.OneToMany; +import lombok.AccessLevel; +import lombok.Getter; +import lombok.NoArgsConstructor; + +import java.util.ArrayList; +import java.util.List; + +@Getter +@Embeddable +public class Announcements { + @OneToMany(mappedBy = "crew", cascade = CascadeType.ALL, orphanRemoval = true) + private List values = new ArrayList<>(); + + public Announcements() { + this.values = createEmptyValues(); + } + + private List createEmptyValues() { + return new ArrayList<>(); + } +} diff --git a/src/main/java/com/retrip/crew/domain/entity/Crew.java b/src/main/java/com/retrip/crew/domain/entity/Crew.java index feb000c..d2c9f28 100644 --- a/src/main/java/com/retrip/crew/domain/entity/Crew.java +++ b/src/main/java/com/retrip/crew/domain/entity/Crew.java @@ -1,9 +1,8 @@ package com.retrip.crew.domain.entity; -import jakarta.persistence.Column; -import jakarta.persistence.Entity; -import jakarta.persistence.Id; -import jakarta.persistence.Version; +import com.retrip.crew.domain.vo.CrewDescription; +import com.retrip.crew.domain.vo.CrewTitle; +import jakarta.persistence.*; import lombok.AccessLevel; import lombok.Getter; import lombok.NoArgsConstructor; @@ -12,24 +11,54 @@ @Entity @NoArgsConstructor(access = AccessLevel.PROTECTED) -@Getter public class Crew extends BaseEntity { @Id @Column(columnDefinition = "varbinary(16)") + @Getter private UUID id; - @Column - private String title; + @Getter + @Embedded + private CrewTitle title; + + @Embedded + @Getter + private CrewDescription description; + + + @Embedded + private CrewMembers crewMembers; + + + @Embedded + private Posts posts; + + @Embedded + private Announcements announcements; + + @Embedded + private Introductions introductions; + @Version private long version; - private Crew(String title) { + private Crew(String name, String description, UUID leader) { this.id = UUID.randomUUID(); - this.title = title; + this.title = new CrewTitle(name); + this.description = new CrewDescription(description); + this.crewMembers = new CrewMembers(this, leader); + this.posts = new Posts(); + this.announcements = new Announcements(); + this.introductions = new Introductions(); } - public static Crew create(String title) { - return new Crew(title); + public static Crew create(String title, String description, UUID leader) { + return new Crew(title, description, leader); } + + public CrewMember getLeader() { + return crewMembers.getLeader(); + } + } diff --git a/src/main/java/com/retrip/crew/domain/entity/CrewMember.java b/src/main/java/com/retrip/crew/domain/entity/CrewMember.java new file mode 100644 index 0000000..7a2c6f1 --- /dev/null +++ b/src/main/java/com/retrip/crew/domain/entity/CrewMember.java @@ -0,0 +1,40 @@ +package com.retrip.crew.domain.entity; + +import jakarta.persistence.*; +import lombok.AccessLevel; +import lombok.Getter; +import lombok.NoArgsConstructor; + +import java.util.List; +import java.util.UUID; + +@Entity +@NoArgsConstructor(access = AccessLevel.PROTECTED, force = true) +@Getter +public class CrewMember extends BaseEntity { + @Id + @Column(columnDefinition = "varbinary(16)") + private UUID id; + + @ManyToOne(fetch = FetchType.LAZY) + @JoinColumn( + name = "crew_id", + nullable = false, + columnDefinition = "varbinary(16)", + foreignKey = @ForeignKey(name = "fk_crew_member_to_crew") + ) + private Crew crew; + + @Column(name = "role", length = 50, nullable = false) + private CrewMemberRole crewMemberRole; + + @Column(nullable = false) + private UUID memberId; + + public CrewMember(Crew crew, UUID memberId, CrewMemberRole crewMemberRole) { + this.id = UUID.randomUUID(); + this.crew = crew; + this.memberId = memberId; + this.crewMemberRole = CrewMemberRole.valueOf(crewMemberRole.name()); + } +} diff --git a/src/main/java/com/retrip/crew/domain/entity/CrewMemberRole.java b/src/main/java/com/retrip/crew/domain/entity/CrewMemberRole.java new file mode 100644 index 0000000..86072f2 --- /dev/null +++ b/src/main/java/com/retrip/crew/domain/entity/CrewMemberRole.java @@ -0,0 +1,25 @@ +package com.retrip.crew.domain.entity; + + +import lombok.AllArgsConstructor; +import lombok.Getter; + +import java.util.Arrays; + +@Getter +@AllArgsConstructor +public enum CrewMemberRole { + LEADER("LEADER", "리더"), + PARTICIPANT("PARTICIPANT", "참가자"); + + private final String code; + private final String viewName; + + public static CrewMemberRole codeOf(String code) { + return Arrays.stream(CrewMemberRole.values()) + .filter(crewMemberRole -> crewMemberRole.getCode().equals(code)) + .findAny() + .orElseThrow(() -> new IllegalArgumentException("존재하지 않는 코드입니다.")); + } +} + diff --git a/src/main/java/com/retrip/crew/domain/entity/CrewMembers.java b/src/main/java/com/retrip/crew/domain/entity/CrewMembers.java new file mode 100644 index 0000000..90feba1 --- /dev/null +++ b/src/main/java/com/retrip/crew/domain/entity/CrewMembers.java @@ -0,0 +1,32 @@ +package com.retrip.crew.domain.entity; + +import jakarta.persistence.CascadeType; +import jakarta.persistence.Embeddable; +import jakarta.persistence.OneToMany; +import lombok.AccessLevel; +import lombok.Getter; +import lombok.NoArgsConstructor; + +import java.util.ArrayList; +import java.util.List; +import java.util.UUID; + +@Getter +@NoArgsConstructor(access = AccessLevel.PROTECTED, force = true) +@Embeddable +public class CrewMembers { + @OneToMany(mappedBy = "crew", cascade = CascadeType.ALL, orphanRemoval = true) + private List values = new ArrayList<>(); + + public CrewMembers(Crew crew, UUID member) { + this.values = createLeader(crew, member); + } + + private List createLeader(Crew crew, UUID memberId) { + return List.of(new CrewMember(crew, memberId, CrewMemberRole.LEADER)); + } + + public CrewMember getLeader() { + return this.values.stream().filter(it -> it.getCrewMemberRole() == CrewMemberRole.LEADER).findFirst().orElse(null); + } +} diff --git a/src/main/java/com/retrip/crew/domain/entity/Introduction.java b/src/main/java/com/retrip/crew/domain/entity/Introduction.java new file mode 100644 index 0000000..1753df1 --- /dev/null +++ b/src/main/java/com/retrip/crew/domain/entity/Introduction.java @@ -0,0 +1,34 @@ +package com.retrip.crew.domain.entity; + +import com.retrip.crew.domain.vo.IntroductionContent; +import com.retrip.crew.domain.vo.IntroductionTitle; +import jakarta.persistence.*; +import lombok.AccessLevel; +import lombok.Getter; +import lombok.NoArgsConstructor; + +import java.util.UUID; + +@Entity +@NoArgsConstructor(access = AccessLevel.PROTECTED) +@Getter +public class Introduction extends BaseEntity { + @Id + @Column(columnDefinition = "varbinary(16)") + private UUID id; + + @Embedded + private IntroductionTitle title; + + @Embedded + private IntroductionContent content; + + @ManyToOne(fetch = FetchType.LAZY) + @JoinColumn( + name = "crew_id", + nullable = false, + columnDefinition = "varbinary(16)", + foreignKey = @ForeignKey(name = "fk_self_introduce_board_to_crew") + ) + private Crew crew; +} diff --git a/src/main/java/com/retrip/crew/domain/entity/Introductions.java b/src/main/java/com/retrip/crew/domain/entity/Introductions.java new file mode 100644 index 0000000..6d269aa --- /dev/null +++ b/src/main/java/com/retrip/crew/domain/entity/Introductions.java @@ -0,0 +1,24 @@ +package com.retrip.crew.domain.entity; + +import jakarta.persistence.CascadeType; +import jakarta.persistence.Embeddable; +import jakarta.persistence.OneToMany; +import lombok.Getter; + +import java.util.ArrayList; +import java.util.List; + +@Getter +@Embeddable +public class Introductions { + @OneToMany(mappedBy = "crew", cascade = CascadeType.ALL, orphanRemoval = true) + private List values = new ArrayList<>(); + + public Introductions() { + this.values = createEmptyValues(); + } + + private List createEmptyValues() { + return new ArrayList<>(); + } +} diff --git a/src/main/java/com/retrip/crew/domain/entity/Post.java b/src/main/java/com/retrip/crew/domain/entity/Post.java new file mode 100644 index 0000000..8bcf102 --- /dev/null +++ b/src/main/java/com/retrip/crew/domain/entity/Post.java @@ -0,0 +1,34 @@ +package com.retrip.crew.domain.entity; + +import com.retrip.crew.domain.vo.PostContent; +import com.retrip.crew.domain.vo.PostTitle; +import jakarta.persistence.*; +import lombok.AccessLevel; +import lombok.Getter; +import lombok.NoArgsConstructor; + +import java.util.UUID; + +@Entity +@NoArgsConstructor(access = AccessLevel.PROTECTED) +@Getter +public class Post extends BaseEntity { + @Id + @Column(columnDefinition = "varbinary(16)") + private UUID id; + + @Embedded + private PostTitle title; + + @Embedded + private PostContent content; + + @ManyToOne(fetch = FetchType.LAZY) + @JoinColumn( + name = "crew_id", + nullable = false, + columnDefinition = "varbinary(16)", + foreignKey = @ForeignKey(name = "fk_free_board_to_crew") + ) + private Crew crew; +} diff --git a/src/main/java/com/retrip/crew/domain/entity/Posts.java b/src/main/java/com/retrip/crew/domain/entity/Posts.java new file mode 100644 index 0000000..39b9b9b --- /dev/null +++ b/src/main/java/com/retrip/crew/domain/entity/Posts.java @@ -0,0 +1,26 @@ +package com.retrip.crew.domain.entity; + +import jakarta.persistence.CascadeType; +import jakarta.persistence.Embeddable; +import jakarta.persistence.OneToMany; +import lombok.AccessLevel; +import lombok.Getter; +import lombok.NoArgsConstructor; + +import java.util.ArrayList; +import java.util.List; + +@Getter +@Embeddable +public class Posts { + @OneToMany(mappedBy = "crew", cascade = CascadeType.ALL, orphanRemoval = true) + private List values = new ArrayList<>(); + + public Posts() { + this.values = createEmptyValues(); + } + + private List createEmptyValues() { + return new ArrayList<>(); + } +} diff --git a/src/main/java/com/retrip/crew/domain/exception/AnnouncementContentException.java b/src/main/java/com/retrip/crew/domain/exception/AnnouncementContentException.java new file mode 100644 index 0000000..554d584 --- /dev/null +++ b/src/main/java/com/retrip/crew/domain/exception/AnnouncementContentException.java @@ -0,0 +1,8 @@ +package com.retrip.crew.domain.exception; + +public class AnnouncementContentException extends CrewException { + + public AnnouncementContentException(String message) { + super(CrewErrorCode.ANNOUNCEMENT_CONTENT_ERROR, message); + } +} diff --git a/src/main/java/com/retrip/crew/domain/exception/AnnouncementTitleException.java b/src/main/java/com/retrip/crew/domain/exception/AnnouncementTitleException.java new file mode 100644 index 0000000..571ae90 --- /dev/null +++ b/src/main/java/com/retrip/crew/domain/exception/AnnouncementTitleException.java @@ -0,0 +1,8 @@ +package com.retrip.crew.domain.exception; + +public class AnnouncementTitleException extends CrewException { + + public AnnouncementTitleException(String message) { + super(CrewErrorCode.ANNOUNCEMENT_TITLE_ERROR, message); + } +} diff --git a/src/main/java/com/retrip/crew/domain/exception/CrewDescriptionException.java b/src/main/java/com/retrip/crew/domain/exception/CrewDescriptionException.java new file mode 100644 index 0000000..04db44e --- /dev/null +++ b/src/main/java/com/retrip/crew/domain/exception/CrewDescriptionException.java @@ -0,0 +1,8 @@ +package com.retrip.crew.domain.exception; + +public class CrewDescriptionException extends CrewException { + + public CrewDescriptionException(String message) { + super(CrewErrorCode.CREW_DESCRIPTION_ERROR, message); + } +} diff --git a/src/main/java/com/retrip/crew/domain/exception/CrewErrorCode.java b/src/main/java/com/retrip/crew/domain/exception/CrewErrorCode.java new file mode 100644 index 0000000..d494b90 --- /dev/null +++ b/src/main/java/com/retrip/crew/domain/exception/CrewErrorCode.java @@ -0,0 +1,17 @@ +package com.retrip.crew.domain.exception; + +public enum CrewErrorCode { + CREW_TITLE_ERROR(1001), + CREW_DESCRIPTION_ERROR(1002), + POST_TITLE_ERROR(1003), + POST_CONTENT_ERROR(1004), + ANNOUNCEMENT_TITLE_ERROR(1005), + ANNOUNCEMENT_CONTENT_ERROR(1006), + INTRODUCTION_TITLE_ERROR(1007), + INTRODUCTION_CONTENT_ERROR(1008); + + private final int code; + CrewErrorCode(int code) { + this.code = code; + } +} diff --git a/src/main/java/com/retrip/crew/domain/exception/CrewException.java b/src/main/java/com/retrip/crew/domain/exception/CrewException.java new file mode 100644 index 0000000..6b851e9 --- /dev/null +++ b/src/main/java/com/retrip/crew/domain/exception/CrewException.java @@ -0,0 +1,10 @@ +package com.retrip.crew.domain.exception; + +public abstract class CrewException extends RuntimeException { + private final CrewErrorCode errorCode; + + public CrewException(CrewErrorCode errorCode, String message) { + super(message); + this.errorCode = errorCode; + } +} diff --git a/src/main/java/com/retrip/crew/domain/exception/CrewTitleException.java b/src/main/java/com/retrip/crew/domain/exception/CrewTitleException.java new file mode 100644 index 0000000..ae1c0c1 --- /dev/null +++ b/src/main/java/com/retrip/crew/domain/exception/CrewTitleException.java @@ -0,0 +1,7 @@ +package com.retrip.crew.domain.exception; + +public class CrewTitleException extends CrewException { + public CrewTitleException(String message) { + super(CrewErrorCode.CREW_TITLE_ERROR, message); + } +} diff --git a/src/main/java/com/retrip/crew/domain/exception/IntroductionContentException.java b/src/main/java/com/retrip/crew/domain/exception/IntroductionContentException.java new file mode 100644 index 0000000..ab07f4b --- /dev/null +++ b/src/main/java/com/retrip/crew/domain/exception/IntroductionContentException.java @@ -0,0 +1,9 @@ +package com.retrip.crew.domain.exception; + +public class IntroductionContentException extends CrewException { + private static final int ERROR_CODE = 1003; + + public IntroductionContentException(String message) { + super(CrewErrorCode.INTRODUCTION_CONTENT_ERROR, message); + } +} diff --git a/src/main/java/com/retrip/crew/domain/exception/IntroductionTitleException.java b/src/main/java/com/retrip/crew/domain/exception/IntroductionTitleException.java new file mode 100644 index 0000000..6d7af3e --- /dev/null +++ b/src/main/java/com/retrip/crew/domain/exception/IntroductionTitleException.java @@ -0,0 +1,9 @@ +package com.retrip.crew.domain.exception; + +public class IntroductionTitleException extends CrewException { + private static final int ERROR_CODE = 1003; + + public IntroductionTitleException(String message) { + super(CrewErrorCode.INTRODUCTION_TITLE_ERROR, message); + } +} diff --git a/src/main/java/com/retrip/crew/domain/exception/PostContentException.java b/src/main/java/com/retrip/crew/domain/exception/PostContentException.java new file mode 100644 index 0000000..997f665 --- /dev/null +++ b/src/main/java/com/retrip/crew/domain/exception/PostContentException.java @@ -0,0 +1,8 @@ +package com.retrip.crew.domain.exception; + +public class PostContentException extends CrewException { + + public PostContentException(String message) { + super(CrewErrorCode.POST_CONTENT_ERROR, message); + } +} diff --git a/src/main/java/com/retrip/crew/domain/exception/PostTitleException.java b/src/main/java/com/retrip/crew/domain/exception/PostTitleException.java new file mode 100644 index 0000000..64afe6c --- /dev/null +++ b/src/main/java/com/retrip/crew/domain/exception/PostTitleException.java @@ -0,0 +1,8 @@ +package com.retrip.crew.domain.exception; + +public class PostTitleException extends CrewException { + + public PostTitleException(String message) { + super(CrewErrorCode.POST_TITLE_ERROR, message); + } +} diff --git a/src/main/java/com/retrip/crew/domain/vo/AnnouncementContent.java b/src/main/java/com/retrip/crew/domain/vo/AnnouncementContent.java new file mode 100644 index 0000000..e213e0d --- /dev/null +++ b/src/main/java/com/retrip/crew/domain/vo/AnnouncementContent.java @@ -0,0 +1,31 @@ +package com.retrip.crew.domain.vo; + +import com.retrip.crew.domain.exception.CrewDescriptionException; +import jakarta.persistence.Column; +import jakarta.persistence.Embeddable; +import lombok.AccessLevel; +import lombok.EqualsAndHashCode; +import lombok.Getter; +import lombok.NoArgsConstructor; + +@Getter +@Embeddable +@EqualsAndHashCode +@NoArgsConstructor(access = AccessLevel.PROTECTED, force = true) +public class AnnouncementContent { + private static final int CONTENT_LENGTH_LIMIT = 300; + + @Column(name = "content", nullable = false, length = CONTENT_LENGTH_LIMIT) + private final String value; + + public AnnouncementContent(String value) { + validate(value); + this.value = value; + } + + private void validate(String value) { + if (value.length() > CONTENT_LENGTH_LIMIT) { + throw new CrewDescriptionException("공지 게시글 내용은 " + CONTENT_LENGTH_LIMIT + "자를 넘을 수 없습니다."); + } + } +} diff --git a/src/main/java/com/retrip/crew/domain/vo/AnnouncementTitle.java b/src/main/java/com/retrip/crew/domain/vo/AnnouncementTitle.java new file mode 100644 index 0000000..7aabaf1 --- /dev/null +++ b/src/main/java/com/retrip/crew/domain/vo/AnnouncementTitle.java @@ -0,0 +1,31 @@ +package com.retrip.crew.domain.vo; + +import com.retrip.crew.domain.exception.IntroductionTitleException; +import jakarta.persistence.Column; +import jakarta.persistence.Embeddable; +import lombok.AccessLevel; +import lombok.EqualsAndHashCode; +import lombok.Getter; +import lombok.NoArgsConstructor; + +@Getter +@Embeddable +@EqualsAndHashCode +@NoArgsConstructor(access = AccessLevel.PROTECTED, force = true) +public class AnnouncementTitle { + private static final int TITLE_LENGTH_LIMIT = 20; + + @Column(name = "title", nullable = false, length = TITLE_LENGTH_LIMIT) + private final String value; + + public AnnouncementTitle(String value) { + validate(value); + this.value = value; + } + + private void validate(String value) { + if (value.length() > TITLE_LENGTH_LIMIT) { + throw new IntroductionTitleException("공지 게시글 제목은 " + TITLE_LENGTH_LIMIT + "자를 넘을 수 없습니다."); + } + } +} diff --git a/src/main/java/com/retrip/crew/domain/vo/CrewDescription.java b/src/main/java/com/retrip/crew/domain/vo/CrewDescription.java new file mode 100644 index 0000000..76c0eb9 --- /dev/null +++ b/src/main/java/com/retrip/crew/domain/vo/CrewDescription.java @@ -0,0 +1,31 @@ +package com.retrip.crew.domain.vo; + +import com.retrip.crew.domain.exception.CrewDescriptionException; +import jakarta.persistence.Column; +import jakarta.persistence.Embeddable; +import lombok.AccessLevel; +import lombok.EqualsAndHashCode; +import lombok.Getter; +import lombok.NoArgsConstructor; + +@Getter +@Embeddable +@EqualsAndHashCode +@NoArgsConstructor(access = AccessLevel.PROTECTED, force = true) +public class CrewDescription { + private static final int DESCRIPTION_LENGTH_LIMIT = 200; + + @Column(name = "description", nullable = false, length = DESCRIPTION_LENGTH_LIMIT) + private final String value; + + public CrewDescription(String value) { + validate(value); + this.value = value; + } + + private void validate(String value) { + if (value.length() > DESCRIPTION_LENGTH_LIMIT) { + throw new CrewDescriptionException("크루 상세 설명은 " + DESCRIPTION_LENGTH_LIMIT + "자를 넘을 수 없습니다."); + } + } +} diff --git a/src/main/java/com/retrip/crew/domain/vo/CrewTitle.java b/src/main/java/com/retrip/crew/domain/vo/CrewTitle.java new file mode 100644 index 0000000..50cdbac --- /dev/null +++ b/src/main/java/com/retrip/crew/domain/vo/CrewTitle.java @@ -0,0 +1,31 @@ +package com.retrip.crew.domain.vo; + +import com.retrip.crew.domain.exception.CrewTitleException; +import jakarta.persistence.Column; +import jakarta.persistence.Embeddable; +import lombok.AccessLevel; +import lombok.EqualsAndHashCode; +import lombok.Getter; +import lombok.NoArgsConstructor; + +@Getter +@Embeddable +@EqualsAndHashCode +@NoArgsConstructor(access = AccessLevel.PROTECTED, force = true) +public class CrewTitle { + private static final int TITLE_LENGTH_LIMIT = 30; + + @Column(name = "title", nullable = false, length = TITLE_LENGTH_LIMIT) + private final String value; + + public CrewTitle(String value) { + validate(value); + this.value = value; + } + + private void validate(String value) { + if (value.length() > TITLE_LENGTH_LIMIT) { + throw new CrewTitleException("크루 제목은 " + TITLE_LENGTH_LIMIT + "자를 넘을 수 없습니다."); + } + } +} diff --git a/src/main/java/com/retrip/crew/domain/vo/IntroductionContent.java b/src/main/java/com/retrip/crew/domain/vo/IntroductionContent.java new file mode 100644 index 0000000..6001175 --- /dev/null +++ b/src/main/java/com/retrip/crew/domain/vo/IntroductionContent.java @@ -0,0 +1,31 @@ +package com.retrip.crew.domain.vo; + +import com.retrip.crew.domain.exception.CrewDescriptionException; +import jakarta.persistence.Column; +import jakarta.persistence.Embeddable; +import lombok.AccessLevel; +import lombok.EqualsAndHashCode; +import lombok.Getter; +import lombok.NoArgsConstructor; + +@Getter +@Embeddable +@EqualsAndHashCode +@NoArgsConstructor(access = AccessLevel.PROTECTED, force = true) +public class IntroductionContent { + private static final int CONTENT_LENGTH_LIMIT = 500; + + @Column(name = "content", nullable = false, length = CONTENT_LENGTH_LIMIT) + private final String value; + + public IntroductionContent(String value) { + validate(value); + this.value = value; + } + + private void validate(String value) { + if (value.length() > CONTENT_LENGTH_LIMIT) { + throw new CrewDescriptionException("자기 소개 게시글 내용은 " + CONTENT_LENGTH_LIMIT + "자를 넘을 수 없습니다."); + } + } +} diff --git a/src/main/java/com/retrip/crew/domain/vo/IntroductionTitle.java b/src/main/java/com/retrip/crew/domain/vo/IntroductionTitle.java new file mode 100644 index 0000000..7668e76 --- /dev/null +++ b/src/main/java/com/retrip/crew/domain/vo/IntroductionTitle.java @@ -0,0 +1,32 @@ +package com.retrip.crew.domain.vo; + +import com.retrip.crew.domain.exception.CrewTitleException; +import com.retrip.crew.domain.exception.IntroductionTitleException; +import jakarta.persistence.Column; +import jakarta.persistence.Embeddable; +import lombok.AccessLevel; +import lombok.EqualsAndHashCode; +import lombok.Getter; +import lombok.NoArgsConstructor; + +@Getter +@Embeddable +@EqualsAndHashCode +@NoArgsConstructor(access = AccessLevel.PROTECTED, force = true) +public class IntroductionTitle { + private static final int TITLE_LENGTH_LIMIT = 20; + + @Column(name = "title", nullable = false, length = TITLE_LENGTH_LIMIT) + private final String value; + + public IntroductionTitle(String value) { + validate(value); + this.value = value; + } + + private void validate(String value) { + if (value.length() > TITLE_LENGTH_LIMIT) { + throw new IntroductionTitleException("자기 소개 게시글 제목은 " + TITLE_LENGTH_LIMIT + "자를 넘을 수 없습니다."); + } + } +} diff --git a/src/main/java/com/retrip/crew/domain/vo/NotificationBoardContent.java b/src/main/java/com/retrip/crew/domain/vo/NotificationBoardContent.java new file mode 100644 index 0000000..eeb7017 --- /dev/null +++ b/src/main/java/com/retrip/crew/domain/vo/NotificationBoardContent.java @@ -0,0 +1,38 @@ +package com.retrip.crew.domain.vo; + +import jakarta.persistence.Column; +import jakarta.persistence.Embeddable; +import lombok.AccessLevel; +import lombok.EqualsAndHashCode; +import lombok.Getter; +import lombok.NoArgsConstructor; + +@Getter +@Embeddable +@EqualsAndHashCode +@NoArgsConstructor(access = AccessLevel.PROTECTED, force = true) +public class NotificationBoardContent { + private static final int TITLE_LENGTH_LIMIT = 30; + private static final int CONTENT_LENGTH_LIMIT = 100; + + @Column(name = "title", nullable = false, length = TITLE_LENGTH_LIMIT) + private final String title; + + @Column(name = "content", nullable = false, length = CONTENT_LENGTH_LIMIT) + private final String content; + + public NotificationBoardContent(String title, String content) { + validate(title, content); + this.title = title; + this.content = content; + } + + private void validate(String title, String content) { + if (title.length() > TITLE_LENGTH_LIMIT) { + throw new IllegalArgumentException("공지 게시글 제목은 " + TITLE_LENGTH_LIMIT + "자를 넘을 수 없습니다."); + } + if (content.length() > CONTENT_LENGTH_LIMIT) { + throw new IllegalArgumentException("공지 게시글 내용은 " + CONTENT_LENGTH_LIMIT + "자를 넘을 수 없습니다."); + } + } +} diff --git a/src/main/java/com/retrip/crew/domain/vo/PostContent.java b/src/main/java/com/retrip/crew/domain/vo/PostContent.java new file mode 100644 index 0000000..65dcb15 --- /dev/null +++ b/src/main/java/com/retrip/crew/domain/vo/PostContent.java @@ -0,0 +1,31 @@ +package com.retrip.crew.domain.vo; + +import com.retrip.crew.domain.exception.CrewDescriptionException; +import jakarta.persistence.Column; +import jakarta.persistence.Embeddable; +import lombok.AccessLevel; +import lombok.EqualsAndHashCode; +import lombok.Getter; +import lombok.NoArgsConstructor; + +@Getter +@Embeddable +@EqualsAndHashCode +@NoArgsConstructor(access = AccessLevel.PROTECTED, force = true) +public class PostContent { + private static final int CONTENT_LENGTH_LIMIT = 500; + + @Column(name = "content", nullable = false, length = CONTENT_LENGTH_LIMIT) + private final String value; + + public PostContent(String value) { + validate(value); + this.value = value; + } + + private void validate(String value) { + if (value.length() > CONTENT_LENGTH_LIMIT) { + throw new CrewDescriptionException("자유 게시판 내용은 " + CONTENT_LENGTH_LIMIT + "자를 넘을 수 없습니다."); + } + } +} diff --git a/src/main/java/com/retrip/crew/domain/vo/PostTitle.java b/src/main/java/com/retrip/crew/domain/vo/PostTitle.java new file mode 100644 index 0000000..5d2f757 --- /dev/null +++ b/src/main/java/com/retrip/crew/domain/vo/PostTitle.java @@ -0,0 +1,31 @@ +package com.retrip.crew.domain.vo; + +import com.retrip.crew.domain.exception.IntroductionTitleException; +import jakarta.persistence.Column; +import jakarta.persistence.Embeddable; +import lombok.AccessLevel; +import lombok.EqualsAndHashCode; +import lombok.Getter; +import lombok.NoArgsConstructor; + +@Getter +@Embeddable +@EqualsAndHashCode +@NoArgsConstructor(access = AccessLevel.PROTECTED, force = true) +public class PostTitle { + private static final int TITLE_LENGTH_LIMIT = 20; + + @Column(name = "title", nullable = false, length = TITLE_LENGTH_LIMIT) + private final String value; + + public PostTitle(String value) { + validate(value); + this.value = value; + } + + private void validate(String value) { + if (value.length() > TITLE_LENGTH_LIMIT) { + throw new IntroductionTitleException("자유 게시판 제목은 " + TITLE_LENGTH_LIMIT + "자를 넘을 수 없습니다."); + } + } +} diff --git a/src/test/java/com/retrip/crew/CrewApplicationTests.java b/src/test/java/com/retrip/crew/CrewApplicationTests.java index 76c2982..405f037 100644 --- a/src/test/java/com/retrip/crew/CrewApplicationTests.java +++ b/src/test/java/com/retrip/crew/CrewApplicationTests.java @@ -3,9 +3,8 @@ import com.retrip.crew.domain.entity.Crew; import org.junit.jupiter.api.DisplayName; import org.junit.jupiter.api.Test; -import org.springframework.boot.test.context.SpringBootTest; -import java.time.LocalDate; +import java.util.UUID; import static org.assertj.core.api.Assertions.assertThatCode; @@ -13,7 +12,11 @@ class CrewApplicationTests { @DisplayName("제목을 입력해 크루를 생성할 수 있다.") @Test void create() { - assertThatCode(() -> Crew.create("속초 크루 모집")).doesNotThrowAnyException(); + assertThatCode(() -> Crew.create( + "인천 크루 모집", + "인천 크루원을 모집합니다.\n 가입나이: 20~29살 \n 금지 사항\n - 연애 금지\n - 만남 당일 취소 금지\n - 사적 연락 금지", + UUID.randomUUID() + )).doesNotThrowAnyException(); } } diff --git a/src/test/java/com/retrip/crew/application/in/CrewServiceTest.java b/src/test/java/com/retrip/crew/application/in/CrewServiceTest.java new file mode 100644 index 0000000..df9bf29 --- /dev/null +++ b/src/test/java/com/retrip/crew/application/in/CrewServiceTest.java @@ -0,0 +1,44 @@ +package com.retrip.crew.application.in; + +import com.retrip.crew.application.in.request.CrewCreateRequest; +import com.retrip.crew.application.in.response.CrewCreateResponse; +import com.retrip.crew.application.out.repository.CrewRepository; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.autoconfigure.jdbc.AutoConfigureTestDatabase; +import org.springframework.boot.test.autoconfigure.orm.jpa.DataJpaTest; + +import java.util.UUID; + +import static org.assertj.core.api.Assertions.assertThat; + +@DataJpaTest +@AutoConfigureTestDatabase(replace = AutoConfigureTestDatabase.Replace.NONE) +class CrewServiceTest { + @Autowired + CrewRepository crewRepository; + + CrewService crewService; + UUID memberId = UUID.randomUUID(); + + @BeforeEach + void setUp() { + crewService = new CrewService(crewRepository); + } + + @DisplayName("크루를 생성 한다.") + @Test + void createCrew() { + CrewCreateRequest request = new CrewCreateRequest( + memberId, + "속초 크루원 구함", + "속초 친구 구합니다! 나이는 20~40.. 많은 가입 부탁드립니다." + ); + CrewCreateResponse response = crewService.createCrew(request); + + assertThat(response.id()).isNotNull(); + assertThat(response.leaderId()).isNotNull(); + } +} diff --git a/src/test/java/com/retrip/crew/domain/entity/CrewTest.java b/src/test/java/com/retrip/crew/domain/entity/CrewTest.java index eb2edcf..2c89485 100644 --- a/src/test/java/com/retrip/crew/domain/entity/CrewTest.java +++ b/src/test/java/com/retrip/crew/domain/entity/CrewTest.java @@ -1,7 +1,20 @@ package com.retrip.crew.domain.entity; -import static org.junit.jupiter.api.Assertions.*; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; + +import java.util.UUID; + +import static org.assertj.core.api.AssertionsForClassTypes.assertThatCode; class CrewTest { + @DisplayName("크루 생성 테스트") + @Test + public void create() { + assertThatCode(() -> Crew.create( + "속초 크루원 구함", + "속초 친구 구합니다! 나이는 20~40.. 많은 가입 부탁드립니다.", + UUID.randomUUID())).doesNotThrowAnyException(); + } } diff --git a/src/test/java/com/retrip/crew/domain/vo/CrewIntroductionTitleTest.java b/src/test/java/com/retrip/crew/domain/vo/CrewIntroductionTitleTest.java new file mode 100644 index 0000000..694e249 --- /dev/null +++ b/src/test/java/com/retrip/crew/domain/vo/CrewIntroductionTitleTest.java @@ -0,0 +1,16 @@ +package com.retrip.crew.domain.vo; + +import com.retrip.crew.domain.exception.CrewTitleException; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; + +import static org.assertj.core.api.AssertionsForClassTypes.assertThatThrownBy; + +class CrewIntroductionTitleTest { + + @Test + @DisplayName("크루 이름은 30자 미만으로 설정해야한다.") + public void validateName() { + assertThatThrownBy(() -> new CrewTitle("통천, 회양, 평강, 이천, 김화, 철원, 양구, 인제, 고성, 강릉, 속초 등 크루 인원 모집합니다.")).isExactlyInstanceOf(CrewTitleException.class); + } +}