Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[feat] 게시글 작성 api 구현 #26

Merged
merged 12 commits into from
Jan 6, 2024
5 changes: 4 additions & 1 deletion build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,9 @@ dependencies {

// redis
implementation 'org.springframework.boot:spring-boot-starter-data-redis'

// validate
implementation 'org.springframework.boot:spring-boot-starter-validation'
}

tasks.named('test') {
Expand All @@ -93,4 +96,4 @@ sourceSets {
// gradle clean 시에 QClass 디렉토리 삭제
clean {
delete file(generated)
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
import jakarta.persistence.*;
import lombok.*;
import org.gachon.checkmate.domain.checkList.converter.*;
import org.gachon.checkmate.domain.checkList.dto.request.CheckListRequestDto;
import org.gachon.checkmate.domain.post.entity.Post;
import org.gachon.checkmate.global.common.BaseTimeEntity;

Expand Down Expand Up @@ -31,4 +32,18 @@ public class PostCheckList extends BaseTimeEntity {
@OneToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "post_id")
private Post post;

public static PostCheckList createPostCheckList(CheckListRequestDto checkListRequestDto, Post post) {
PostCheckList checkList = PostCheckList.builder()
.cleanType(checkListRequestDto.cleanType())
.drinkType(checkListRequestDto.drinkType())
.homeType(checkListRequestDto.homeType())
.lifePatterType(checkListRequestDto.lifePatterType())
.noiseType(checkListRequestDto.noiseType())
.sleepType(checkListRequestDto.sleepType())
.post(post)
.build();
post.setPostCheckList(checkList);
return checkList;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
package org.gachon.checkmate.domain.checkList.repository;

import org.gachon.checkmate.domain.checkList.entity.PostCheckList;
import org.springframework.data.jpa.repository.JpaRepository;

public interface PostCheckListRepository extends JpaRepository<PostCheckList, Long> {
}
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@
import org.gachon.checkmate.domain.checkList.entity.CheckList;
import org.gachon.checkmate.domain.member.converter.GenderTypeConverter;
import org.gachon.checkmate.domain.member.converter.MbtiTypeConverter;
import org.gachon.checkmate.domain.post.converter.RoomTypeConverter;
import org.gachon.checkmate.domain.post.entity.Post;
import org.gachon.checkmate.domain.scrap.entity.Scrap;
import org.gachon.checkmate.global.common.BaseTimeEntity;
Expand Down Expand Up @@ -43,7 +42,7 @@ public class User extends BaseTimeEntity {
@Builder.Default
private List<Scrap> scrapList = new ArrayList<>();

public static User createUser(String email, String storedPassword, String name, String school, String major, MbtiType mbti, GenderType gender, String profile){
public static User createUser(String email, String storedPassword, String name, String school, String major, MbtiType mbti, GenderType gender, String profile) {
return User.builder()
.email(email)
.password(storedPassword)
Expand All @@ -64,7 +63,11 @@ public void setCheckList(CheckList checkList) {
this.checkList = checkList;
}

public void setProfile(String profile){
public void setProfile(String profile) {
this.profile = profile;
}

public void addPost(Post post) {
this.postList.add(post);
}
}
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
package org.gachon.checkmate.domain.post.controller;

import jakarta.validation.Valid;
import lombok.RequiredArgsConstructor;
import org.gachon.checkmate.domain.post.dto.request.PostCreateRequestDto;
import org.gachon.checkmate.domain.post.dto.response.PostDetailResponseDto;
import org.gachon.checkmate.domain.post.dto.response.PostSearchResponseDto;
import org.gachon.checkmate.domain.post.service.PostService;
Expand Down Expand Up @@ -46,4 +48,11 @@ public ResponseEntity<SuccessResponse<?>> searchKeyWordPost(@UserId final Long u
final PostSearchResponseDto responseDto = postService.searchKeyWordPost(userId, key, type, pageable);
return SuccessResponse.ok(responseDto);
}

@PostMapping
public ResponseEntity<SuccessResponse<?>> createPost(@UserId final Long userId,
@Valid @RequestBody final PostCreateRequestDto requestDto) {
postService.createPost(userId, requestDto);
return SuccessResponse.ok(null);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
package org.gachon.checkmate.domain.post.dto.request;

import jakarta.validation.constraints.NotBlank;
import jakarta.validation.constraints.NotNull;

import lombok.NonNull;
import org.gachon.checkmate.domain.checkList.dto.request.CheckListRequestDto;
import org.gachon.checkmate.domain.post.entity.ImportantKeyType;
import org.gachon.checkmate.domain.post.entity.RoomType;
import org.gachon.checkmate.domain.post.entity.SimilarityKeyType;

import java.time.LocalDate;

public record PostCreateRequestDto(
@NotBlank(message = "제목을 입력해주세요") String title,
@NotBlank(message = "내용을 입력해주세요") String content,
@NotNull(message = "중요 키워드를 입력해주세요") ImportantKeyType importantKey,
@NotNull(message = "유사도를 입력해주세요") SimilarityKeyType similarityKey,
@NotNull(message = "기숙사 유형을 입력해주세요") RoomType roomType,
@NotNull(message = "모집 마감기간을 입력해주세요") LocalDate endDate,
@NotNull(message = "체크리스트를 입력해주세요") CheckListRequestDto checkList
) {
}
21 changes: 20 additions & 1 deletion src/main/java/org/gachon/checkmate/domain/post/entity/Post.java
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,11 @@
import jakarta.persistence.*;
import lombok.*;
import org.gachon.checkmate.domain.checkList.entity.PostCheckList;
import org.gachon.checkmate.domain.post.converter.RoomTypeConverter;
import org.gachon.checkmate.domain.member.entity.User;
import org.gachon.checkmate.domain.post.converter.ImportantKeyTypeConverter;
import org.gachon.checkmate.domain.post.converter.RoomTypeConverter;
import org.gachon.checkmate.domain.post.converter.SimilarityKeyTypeConverter;
import org.gachon.checkmate.domain.post.dto.request.PostCreateRequestDto;
import org.gachon.checkmate.domain.scrap.entity.Scrap;
import org.gachon.checkmate.global.common.BaseTimeEntity;

Expand Down Expand Up @@ -41,4 +42,22 @@ public class Post extends BaseTimeEntity {
@OneToMany(mappedBy = "post")
@Builder.Default
private List<Scrap> scrapList = new ArrayList<>();

public static Post createPost(PostCreateRequestDto postCreateRequestDto, User user) {
Post post = Post.builder()
.title(postCreateRequestDto.title())
.content(postCreateRequestDto.content())
.endDate(postCreateRequestDto.endDate())
.roomType(postCreateRequestDto.roomType())
.importantKeyType(postCreateRequestDto.importantKey())
.similarityKeyType(postCreateRequestDto.similarityKey())
.user(user)
.build();
user.addPost(post);
return post;
}

public void setPostCheckList(PostCheckList postCheckList) {
this.postCheckList = postCheckList;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ public Optional<PostDetailDto> findPostDetail(Long postId) {
.leftJoin(post.postCheckList, postCheckList)
.leftJoin(post.user, user)
.where(
containPostId(postId)
eqPostId(postId)
)
.fetchOne());
}
Expand Down Expand Up @@ -123,7 +123,7 @@ public Page<PostSearchDto> searchTextPost(String text, Pageable pageable) {
return PageableExecutionUtils.getPage(content, pageable, countQuery::fetchCount);
}

private BooleanExpression containPostId(Long postId) {
private BooleanExpression eqPostId(Long postId) {
return post.id.eq(postId);
}

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
package org.gachon.checkmate.domain.post.repository;

import org.gachon.checkmate.domain.post.entity.Post;
import org.springframework.data.jpa.repository.JpaRepository;

import java.util.Optional;

public interface PostRepository extends JpaRepository<Post, Long> {
boolean existsByTitle(String title);
}
RyuKwanKon marked this conversation as resolved.
Show resolved Hide resolved
Original file line number Diff line number Diff line change
@@ -1,19 +1,27 @@
package org.gachon.checkmate.domain.post.service;

import lombok.RequiredArgsConstructor;
import org.gachon.checkmate.domain.checkList.dto.request.CheckListRequestDto;
import org.gachon.checkmate.domain.checkList.dto.response.CheckListResponseDto;
import org.gachon.checkmate.domain.checkList.entity.CheckList;
import org.gachon.checkmate.domain.checkList.entity.PostCheckList;
import org.gachon.checkmate.domain.checkList.repository.CheckListRepository;
import org.gachon.checkmate.domain.checkList.repository.PostCheckListRepository;
import org.gachon.checkmate.domain.member.entity.User;
import org.gachon.checkmate.domain.member.repository.UserRepository;
import org.gachon.checkmate.domain.post.dto.request.PostCreateRequestDto;
import org.gachon.checkmate.domain.post.dto.response.PostDetailResponseDto;
import org.gachon.checkmate.domain.post.dto.response.PostSearchElementResponseDto;
import org.gachon.checkmate.domain.post.dto.response.PostSearchResponseDto;
import org.gachon.checkmate.domain.post.dto.support.PostDetailDto;
import org.gachon.checkmate.domain.post.dto.support.PostSearchDto;
import org.gachon.checkmate.domain.post.entity.ImportantKeyType;
import org.gachon.checkmate.domain.post.entity.Post;
import org.gachon.checkmate.domain.post.entity.SortType;
import org.gachon.checkmate.domain.post.repository.PostQuerydslRepository;
import org.gachon.checkmate.domain.post.repository.PostRepository;
import org.gachon.checkmate.global.error.exception.EntityNotFoundException;
import org.gachon.checkmate.global.error.exception.InvalidValueException;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.stereotype.Service;
Expand All @@ -26,8 +34,7 @@
import java.util.Objects;
import java.util.stream.Collectors;

import static org.gachon.checkmate.global.error.ErrorCode.CHECK_LIST_NOT_FOUND;
import static org.gachon.checkmate.global.error.ErrorCode.POST_NOT_FOUND;
import static org.gachon.checkmate.global.error.ErrorCode.*;
import static org.gachon.checkmate.global.utils.EnumValueUtils.toEntityCode;
import static org.gachon.checkmate.global.utils.PagingUtils.convertPaging;

Expand All @@ -36,8 +43,18 @@
@Transactional
@Service
public class PostService {
private final UserRepository userRepository;
private final CheckListRepository checkListRepository;
private final PostRepository postRepository;
private final PostQuerydslRepository postQuerydslRepository;
private final PostCheckListRepository postCheckListRepository;

public void createPost(Long userId, PostCreateRequestDto requestDto) {
validateDuplicateTitle(requestDto.title());
User user = getUserOrThrow(userId);
Post post = createPostAndSave(requestDto, user);
PostCheckList postCheckList = createPostCheckListAndSave(requestDto.checkList(), post);
}

public PostSearchResponseDto getAllPosts(Long userId, String type, Pageable pageable) {
CheckList checkList = getCheckList(userId);
Expand Down Expand Up @@ -130,6 +147,23 @@ private int getRemainDate(LocalDate endDate) {
return (int) endDate.until(LocalDate.now(), ChronoUnit.DAYS);
}

private void validateDuplicateTitle(String title) {
if (postRepository.existsByTitle(title))
throw new InvalidValueException(INVALID_POST_TITLE);
}

private Post createPostAndSave(PostCreateRequestDto postCreateRequestDto, User user) {
Post post = Post.createPost(postCreateRequestDto, user);
postRepository.save(post);
return post;
}

private PostCheckList createPostCheckListAndSave(CheckListRequestDto checkListRequestDto, Post post) {
PostCheckList postCheckList = PostCheckList.createPostCheckList(checkListRequestDto, post);
postCheckListRepository.save(postCheckList);
return postCheckList;
}

private Page<PostSearchDto> getAllPostsResults(Pageable pageable) {
return postQuerydslRepository.findAllPosts(pageable);
}
Expand All @@ -151,4 +185,9 @@ private PostDetailDto getPostDetailDto(Long postId) {
return postQuerydslRepository.findPostDetail(postId)
.orElseThrow(() -> new EntityNotFoundException(POST_NOT_FOUND));
}

private User getUserOrThrow(Long userId) {
return userRepository.findById(userId)
.orElseThrow(() -> new EntityNotFoundException(USER_NOT_FOUND));
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ public enum ErrorCode {
INVALID_ENUM_CODE(HttpStatus.BAD_REQUEST, "잘못된 Enum class code 입니다."),
INVALID_PAGING_SIZE(HttpStatus.BAD_REQUEST, "잘못된 Paging 크기입니다."),
INVALID_PASSWORD(HttpStatus.BAD_REQUEST, "비밀번호는 8~20자 대소문자 영문, 숫자, 특수문자의 조합이어야 합니다."),
INVALID_POST_TITLE(HttpStatus.BAD_REQUEST, "이미 존재하는 게시물입니다."),

/**
* 401 Unauthorized
Expand Down