diff --git a/src/main/java/com/example/sharemind/post/application/PostService.java b/src/main/java/com/example/sharemind/post/application/PostService.java new file mode 100644 index 00000000..642aef26 --- /dev/null +++ b/src/main/java/com/example/sharemind/post/application/PostService.java @@ -0,0 +1,8 @@ +package com.example.sharemind.post.application; + +import com.example.sharemind.post.dto.request.PostCreateRequest; + +public interface PostService { + + void createPost(PostCreateRequest postCreateRequest, Long customerId); +} diff --git a/src/main/java/com/example/sharemind/post/application/PostServiceImpl.java b/src/main/java/com/example/sharemind/post/application/PostServiceImpl.java new file mode 100644 index 00000000..fe368b38 --- /dev/null +++ b/src/main/java/com/example/sharemind/post/application/PostServiceImpl.java @@ -0,0 +1,29 @@ +package com.example.sharemind.post.application; + +import com.example.sharemind.customer.application.CustomerService; +import com.example.sharemind.customer.domain.Customer; +import com.example.sharemind.global.content.ConsultCategory; +import com.example.sharemind.post.dto.request.PostCreateRequest; +import com.example.sharemind.post.repository.PostRepository; +import lombok.RequiredArgsConstructor; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +@Service +@RequiredArgsConstructor +@Transactional(readOnly = true) +public class PostServiceImpl implements PostService { + + private final PostRepository postRepository; + private final CustomerService customerService; + + @Transactional + @Override + public void createPost(PostCreateRequest postCreateRequest, Long customerId) { + Customer customer = customerService.getCustomerByCustomerId(customerId); + ConsultCategory consultCategory = ConsultCategory.getConsultCategoryByName( + postCreateRequest.getConsultCategory()); + + postRepository.save(postCreateRequest.toEntity(customer, consultCategory)); + } +} diff --git a/src/main/java/com/example/sharemind/post/content/PostStatus.java b/src/main/java/com/example/sharemind/post/content/PostStatus.java new file mode 100644 index 00000000..b8bb9650 --- /dev/null +++ b/src/main/java/com/example/sharemind/post/content/PostStatus.java @@ -0,0 +1,15 @@ +package com.example.sharemind.post.content; + +import lombok.Getter; +import lombok.RequiredArgsConstructor; + +@Getter +@RequiredArgsConstructor +public enum PostStatus { + + PROCEEDING("상담 진행 중"), + COMPLETED("상담 마감"), + REPORTED("신고로 인한 게시 중단"); + + private final String displayName; +} diff --git a/src/main/java/com/example/sharemind/post/domain/Post.java b/src/main/java/com/example/sharemind/post/domain/Post.java new file mode 100644 index 00000000..053531f1 --- /dev/null +++ b/src/main/java/com/example/sharemind/post/domain/Post.java @@ -0,0 +1,81 @@ +package com.example.sharemind.post.domain; + +import com.example.sharemind.customer.domain.Customer; +import com.example.sharemind.global.common.BaseEntity; +import com.example.sharemind.global.content.ConsultCategory; +import com.example.sharemind.post.content.PostStatus; +import jakarta.persistence.Column; +import jakarta.persistence.Entity; +import jakarta.persistence.EnumType; +import jakarta.persistence.Enumerated; +import jakarta.persistence.FetchType; +import jakarta.persistence.GeneratedValue; +import jakarta.persistence.GenerationType; +import jakarta.persistence.Id; +import jakarta.persistence.JoinColumn; +import jakarta.persistence.ManyToOne; +import jakarta.validation.constraints.Size; +import lombok.AccessLevel; +import lombok.Builder; +import lombok.Getter; +import lombok.NoArgsConstructor; + +@NoArgsConstructor(access = AccessLevel.PROTECTED) +@Getter +@Entity +public class Post extends BaseEntity { + + @Id + @GeneratedValue(strategy = GenerationType.IDENTITY) + @Column(name = "post_id") + private Long postId; + + @ManyToOne(fetch = FetchType.LAZY, optional = false) + @JoinColumn(name = "customer_id") + private Customer customer; + + @Column(name = "consult_category", nullable = false) + @Enumerated(EnumType.STRING) + private ConsultCategory consultCategory; + + @Column(nullable = false) + private String title; + + @Size(max = 1000, message = "상담 내용은 최대 1000자입니다.") + @Column(nullable = false) + private String content; + + @Column(nullable = false) + private Long cost; + + @Column(name = "is_public", nullable = false) + private Boolean isPublic; + + @Column(name = "post_status", nullable = false) + @Enumerated(EnumType.STRING) + private PostStatus postStatus; + + @Column(name = "total_like", nullable = false) + private Long totalLike; + + @Column(name = "total_comment", nullable = false) + private Long totalComment; + + @Column(name = "is_paid", nullable = false) + private Boolean isPaid; + + @Builder + public Post(Customer customer, ConsultCategory consultCategory, String title, String content, + Long cost, Boolean isPublic) { + this.customer = customer; + this.consultCategory = consultCategory; + this.title = title; + this.content = content; + this.cost = cost; + this.isPublic = isPublic; + this.postStatus = PostStatus.PROCEEDING; + this.totalLike = 0L; + this.totalComment = 0L; + this.isPaid = false; + } +} diff --git a/src/main/java/com/example/sharemind/post/dto/request/PostCreateRequest.java b/src/main/java/com/example/sharemind/post/dto/request/PostCreateRequest.java new file mode 100644 index 00000000..18f5cc57 --- /dev/null +++ b/src/main/java/com/example/sharemind/post/dto/request/PostCreateRequest.java @@ -0,0 +1,46 @@ +package com.example.sharemind.post.dto.request; + +import com.example.sharemind.customer.domain.Customer; +import com.example.sharemind.global.content.ConsultCategory; +import com.example.sharemind.post.domain.Post; +import io.swagger.v3.oas.annotations.media.Schema; +import jakarta.validation.constraints.NotBlank; +import jakarta.validation.constraints.NotNull; +import jakarta.validation.constraints.Size; +import lombok.Getter; + +@Getter +public class PostCreateRequest { + + @Schema(description = "선택한 상담 카테고리", example = "BOREDOM") + @NotBlank(message = "상담 카테고리는 공백일 수 없습니다.") + private String consultCategory; + + @Schema(description = "상담 제목", example = "남자친구의 심리가 궁금해요") + @NotBlank(message = "상담 제목은 공백일 수 없습니다.") + private String title; + + @Schema(description = "상담 내용", example = "안녕하세요 어쩌구저쩌구~") + @NotBlank(message = "상담 내용은 공백일 수 없습니다.") + @Size(max = 1000, message = "상담 내용은 최대 1000자입니다.") + private String content; + + @Schema(description = "상담료") + @NotNull(message = "상담료는 공백일 수 없습니다.") + private Long cost; + + @Schema(description = "상담 공개 여부", example = "true") + @NotNull(message = "상담 공개 여부는 공백일 수 없습니다.") + private Boolean isPublic; + + public Post toEntity(Customer customer, ConsultCategory consultCategory) { + return Post.builder() + .customer(customer) + .consultCategory(consultCategory) + .title(title) + .content(content) + .cost(cost) + .isPublic(isPublic) + .build(); + } +} diff --git a/src/main/java/com/example/sharemind/post/presentation/PostController.java b/src/main/java/com/example/sharemind/post/presentation/PostController.java new file mode 100644 index 00000000..3d1d6645 --- /dev/null +++ b/src/main/java/com/example/sharemind/post/presentation/PostController.java @@ -0,0 +1,50 @@ +package com.example.sharemind.post.presentation; + +import com.example.sharemind.global.exception.CustomExceptionResponse; +import com.example.sharemind.global.jwt.CustomUserDetails; +import com.example.sharemind.post.application.PostService; +import com.example.sharemind.post.dto.request.PostCreateRequest; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.media.Content; +import io.swagger.v3.oas.annotations.media.Schema; +import io.swagger.v3.oas.annotations.responses.ApiResponse; +import io.swagger.v3.oas.annotations.responses.ApiResponses; +import io.swagger.v3.oas.annotations.tags.Tag; +import jakarta.validation.Valid; +import lombok.RequiredArgsConstructor; +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.RequestBody; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; + +@Tag(name = "Post Controller", description = "일대다 상담 질문 컨트롤러") +@RestController +@RequestMapping("/api/v1/posts") +@RequiredArgsConstructor +public class PostController { + + private final PostService postService; + + @Operation(summary = "일대다 상담 질문 생성", description = "일대다 상담 질문 생성") + @ApiResponses({ + @ApiResponse(responseCode = "201", description = "생성 성공"), + @ApiResponse(responseCode = "400", + description = "1. 요청 값 중 공백이 존재\n 2. 질문 글자수 초과", + content = @Content(mediaType = "application/json", + schema = @Schema(implementation = CustomExceptionResponse.class)) + ), + @ApiResponse(responseCode = "404", description = "1. 존재하지 않는 회원\n 2. 존재하지 않는 상담 카테고리로 요청됨\n", + content = @Content(mediaType = "application/json", + schema = @Schema(implementation = CustomExceptionResponse.class)) + ) + }) + @PostMapping + public ResponseEntity createPost(@Valid @RequestBody PostCreateRequest postCreateRequest, + @AuthenticationPrincipal CustomUserDetails customUserDetails) { + postService.createPost(postCreateRequest, customUserDetails.getCustomer().getCustomerId()); + return ResponseEntity.status(HttpStatus.CREATED).build(); + } +} diff --git a/src/main/java/com/example/sharemind/post/repository/PostRepository.java b/src/main/java/com/example/sharemind/post/repository/PostRepository.java new file mode 100644 index 00000000..aada4502 --- /dev/null +++ b/src/main/java/com/example/sharemind/post/repository/PostRepository.java @@ -0,0 +1,10 @@ +package com.example.sharemind.post.repository; + +import com.example.sharemind.post.domain.Post; +import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.stereotype.Repository; + +@Repository +public interface PostRepository extends JpaRepository { + +}