Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,10 @@ public enum ErrorCode {
// μ’‹μ•„μš”
RECOMMEND_ALREADY_EXISTS(HttpStatus.CONFLICT, "RECOMMEND-001", "이미 μ’‹μ•„μš”λ₯Ό λˆ„λ₯Έ κ²Œμ‹œκΈ€μž…λ‹ˆλ‹€."),
RECOMMEND_NOT_FOUND(HttpStatus.NOT_FOUND, "RECOMMEND-002", "μ’‹μ•„μš” 정보λ₯Ό 찾을 수 μ—†μŠ΅λ‹ˆλ‹€."),
POST_NOT_FOUND(HttpStatus.NOT_FOUND, "POST-001", "ν•΄λ‹Ή κ²Œμ‹œκΈ€μ„ 찾을 수 μ—†μŠ΅λ‹ˆλ‹€."),
RECOMMEND_USER_NOT_FOUND(HttpStatus.NOT_FOUND, "RECOMMEND-003", "μΆ”μ²œν•œ μœ μ €λ₯Ό 찾을 수 μ—†μŠ΅λ‹ˆλ‹€."),

// κ²Œμ‹œκΈ€
POST_NOT_FOUND_BY_ID(HttpStatus.NOT_FOUND,"POST-001", "ν•΄λ‹Ή μ•„μ΄λ””μ˜ κ²Œμ‹œκΈ€μ„ 찾을 수 μ—†μŠ΅λ‹ˆλ‹€"),

// 관심사 선택 μ œν•œ
INTEREST_LIMIT_EXCEEDED(HttpStatus.BAD_REQUEST, "INTEREST-001", "κ΄€μ‹¬μ‚¬λŠ” μ΅œλŒ€ 6κ°œκΉŒμ§€λ§Œ 등둝 κ°€λŠ₯ν•©λ‹ˆλ‹€."),
Expand Down
Original file line number Diff line number Diff line change
@@ -1,54 +1,75 @@
package com.hyetaekon.hyetaekon.post.controller;

import com.hyetaekon.hyetaekon.post.dto.PostDto;
import com.hyetaekon.hyetaekon.common.jwt.CustomUserDetails;
import com.hyetaekon.hyetaekon.post.dto.*;
import com.hyetaekon.hyetaekon.post.entity.PostType;
import com.hyetaekon.hyetaekon.post.service.PostService;
import lombok.RequiredArgsConstructor;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import lombok.extern.slf4j.Slf4j;
import org.springframework.data.web.PageableDefault;
import org.springframework.http.ResponseEntity;
import org.springframework.security.core.annotation.AuthenticationPrincipal;
import org.springframework.web.bind.annotation.*;

import java.util.List;

@Slf4j
@RestController
@RequestMapping("/api/posts")
@RequiredArgsConstructor
public class PostController {

private final PostService postService;

// βœ… κ²Œμ‹œκΈ€ 생성
@PostMapping
public ResponseEntity<PostDto> createPost(@RequestBody PostDto postDto) {
return ResponseEntity.ok(postService.createPost(postDto));
// 전체 κ²Œμ‹œκΈ€ λͺ©λ‘ 쑰회
@GetMapping
public ResponseEntity<Page<PostListResponseDto>> getAllPosts(
@PageableDefault(page = 0, size = 10) Pageable pageable) {
Page<PostListResponseDto> posts = postService.getAllPosts(pageable);
return ResponseEntity.ok(posts);
}

// βœ… νŠΉμ • κ²Œμ‹œκΈ€ 쑰회
@GetMapping("/{postId}")
public ResponseEntity<PostDto> getPost(@PathVariable Long postId) {
return ResponseEntity.ok(postService.getPostById(postId));
// PostType에 ν•΄λ‹Ήν•˜λŠ” κ²Œμ‹œκΈ€ λͺ©λ‘ 쑰회
@GetMapping("/type/{postType}")
public ResponseEntity<Page<PostListResponseDto>> getPostsByType(
@PathVariable PostType postType,
@PageableDefault(page = 0, size = 10) Pageable pageable) {
Page<PostListResponseDto> posts = postService.getPostsByType(postType, pageable);
return ResponseEntity.ok(posts);
}

// βœ… νŠΉμ • μΉ΄ν…Œκ³ λ¦¬μ˜ κ²Œμ‹œκΈ€ 쑰회
@GetMapping("/category/{categoryId}")
public ResponseEntity<List<PostDto>> getPostsByCategory(@PathVariable Long categoryId) {
return ResponseEntity.ok(postService.getPostsByCategoryId(categoryId));
// User, Admin에 따라 λ‹€λ₯Έ μ ‘κ·Ό κ°€λŠ₯
// βœ… νŠΉμ • κ²Œμ‹œκΈ€ 상세 쑰회
@GetMapping("/{postId}")
public ResponseEntity<PostDetailResponseDto> getPost(
@PathVariable Long postId,
@AuthenticationPrincipal CustomUserDetails userDetails) {
return ResponseEntity.ok(postService.getPostById(postId, userDetails.getId()));
}

// βœ… λͺ¨λ“  κ²Œμ‹œκΈ€ 쑰회
@GetMapping
public ResponseEntity<List<PostDto>> getAllPosts() {
return ResponseEntity.ok(postService.getAllPosts());
// βœ… κ²Œμ‹œκΈ€ 생성
@PostMapping
public ResponseEntity<PostDetailResponseDto> createPost(
@RequestBody PostCreateRequestDto requestDto,
@AuthenticationPrincipal CustomUserDetails userDetails) {
return ResponseEntity.ok(postService.createPost(requestDto, userDetails.getId()));
}

// βœ… κ²Œμ‹œκΈ€ μˆ˜μ •
// βœ… κ²Œμ‹œκΈ€ μˆ˜μ • - 본인
@PutMapping("/{postId}")
public ResponseEntity<PostDto> updatePost(@PathVariable Long postId, @RequestBody PostDto postDto) {
return ResponseEntity.ok(postService.updatePost(postId, postDto));
public ResponseEntity<PostDetailResponseDto> updatePost(
@PathVariable Long postId,
@RequestBody PostUpdateRequestDto updateDto,
@AuthenticationPrincipal CustomUserDetails userDetails) {
return ResponseEntity.ok(postService.updatePost(postId, updateDto, userDetails.getId()));
}

// βœ… κ²Œμ‹œκΈ€ μ‚­μ œ (soft delete 방식 μ‚¬μš© κ°€λŠ₯)
// βœ… κ²Œμ‹œκΈ€ μ‚­μ œ (soft delete 방식 μ‚¬μš© κ°€λŠ₯) - 본인 ν˜Ήμ€ κ΄€λ¦¬μž
@DeleteMapping("/{postId}")
public ResponseEntity<Void> deletePost(@PathVariable Long postId) {
postService.deletePost(postId);
public ResponseEntity<Void> deletePost(
@PathVariable Long postId, @AuthenticationPrincipal CustomUserDetails userDetails) {
postService.deletePost(postId, userDetails.getId(), userDetails.getRole());
return ResponseEntity.noContent().build();
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
package com.hyetaekon.hyetaekon.post.dto;

import lombok.*;
import org.springframework.web.multipart.MultipartFile;

import java.time.LocalDateTime;
import java.util.List;

@Getter
@Setter
@Builder
@NoArgsConstructor
@AllArgsConstructor
public class PostCreateRequestDto {
private Long nickName;
private String title;
private String content;
private LocalDateTime createdAt;
private String postType;
private String urlTitle;
private String urlPath;
private String tags;
private List<MultipartFile> images; // 이미지 파일
}
Original file line number Diff line number Diff line change
@@ -1,27 +1,28 @@
package com.hyetaekon.hyetaekon.post.dto;

import lombok.Getter;
import lombok.Setter;

import lombok.*;

import java.time.LocalDateTime;
import java.util.List;

@Getter
@Setter
public class PostDto {
private Long id;
private Long userId;
private String publicServiceId;
@Builder
@NoArgsConstructor
@AllArgsConstructor
public class PostDetailResponseDto {
private Long postId;
private Long nickName; // μž‘μ„±μž λ‹‰λ„€μž„
private String title;
private String content;
private LocalDateTime createdAt;
private LocalDateTime deletedAt; // μ‚­μ œμΌ μΆ”κ°€
private String postType;
private String serviceUrl;
private int recommendCnt;
private int viewCount;
private int viewCnt;
private String urlTitle;
private String urlPath;
private String tags;
private Long categoryId; // 좔가됨
private List<String> imageUrls; // βœ… 이미지 URL 리슀트 μΆ”κ°€
private boolean recommended; // ν˜„μž¬ λ‘œκ·ΈμΈν•œ μ‚¬μš©μžμ˜ μΆ”μ²œ μ—¬λΆ€
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
package com.hyetaekon.hyetaekon.post.dto;

import lombok.*;

import java.time.LocalDateTime;


@Getter
@Builder
@NoArgsConstructor
@AllArgsConstructor
public class PostListResponseDto {
private Long postId;
private String title;
private Long nickName; // μž‘μ„±μž λ‹‰λ„€μž„
private String content;
private LocalDateTime createdAt;
private int viewCnt;
private String postType;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
package com.hyetaekon.hyetaekon.post.dto;

import lombok.*;
import org.springframework.web.multipart.MultipartFile;

import java.time.LocalDateTime;
import java.util.List;

@Getter
@Setter
@Builder
@NoArgsConstructor
@AllArgsConstructor
public class PostUpdateRequestDto {
private Long nickName;
private String title;
private String content;
// private LocalDateTime createdAt;
private String postType;
private String urlTitle;
private String urlPath;
private String tags;
private List<MultipartFile> images; // 이미지 파일
}
61 changes: 52 additions & 9 deletions src/main/java/com/hyetaekon/hyetaekon/post/entity/Post.java
Original file line number Diff line number Diff line change
@@ -1,16 +1,22 @@
package com.hyetaekon.hyetaekon.post.entity;

import com.hyetaekon.hyetaekon.bookmark.entity.Bookmark;
import com.hyetaekon.hyetaekon.publicservice.entity.PublicService;
import com.hyetaekon.hyetaekon.recommend.entity.Recommend;
import com.hyetaekon.hyetaekon.user.entity.User;
import jakarta.persistence.*;
import lombok.Getter;
import lombok.Setter;
import lombok.*;

import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.List;

@Entity
@Getter
@Setter
@Builder
@NoArgsConstructor
@AllArgsConstructor
@Table(name = "post")
public class Post {

Expand All @@ -26,27 +32,36 @@ public class Post {
@JoinColumn(name = "public_service_id")
private PublicService publicService;

@Column(length = 20, nullable = false) // βœ… 제λͺ© 20자 μ œν•œ
@Column(columnDefinition = "VARCHAR(20) CHARACTER SET utf8mb4", nullable = false) // βœ… 제λͺ© 20자 μ œν•œ
private String title;

@Column(length = 500, nullable = false) // βœ… λ‚΄μš© 500자 μ œν•œ
@Column(columnDefinition = "VARCHAR(500) CHARACTER SET utf8mb4", nullable = false) // βœ… λ‚΄μš© 500자 μ œν•œ
private String content;

private LocalDateTime createdAt = LocalDateTime.now();

private LocalDateTime deletedAt;

private int recommendCnt; // μΆ”μ²œμˆ˜
@Builder.Default
@Column(name = "recommend_cnt")
private int recommendCnt = 0; // μΆ”μ²œμˆ˜

@Builder.Default
@Column(name = "view_cnt")
private int viewCnt = 0; // 쑰회수

private int viewCount; // 쑰회수
// TODO: λŒ“κΈ€ 생성/μˆ˜μ • μ‹œ μ—…λ°μ΄νŠΈ
@Builder.Default
@Column(name = "comment_cnt")
private int commentCnt = 0; // λŒ“κΈ€μˆ˜

@Column(name = "post_type")
@Column(name = "post_type", nullable = false)
@Enumerated(EnumType.STRING) // βœ… ENUM νƒ€μž…μœΌλ‘œ μ €μž₯ (질문, 자유, 인사)
private PostType postType;

private String serviceUrl;

@Column(length = 12) // βœ… κ΄€λ ¨ 링크 제λͺ© 12자 μ œν•œ
@Column(columnDefinition = "VARCHAR(12) CHARACTER SET utf8mb4") // βœ… url제λͺ© 12자 μ œν•œ
private String urlTitle;

private String urlPath;
Expand All @@ -57,6 +72,34 @@ public class Post {
@Column(name = "category_id")
private Long categoryId;

@Builder.Default
@OneToMany(mappedBy = "post", cascade = CascadeType.ALL, orphanRemoval = true)
private List<PostImage> postImages = new ArrayList<>(); // βœ… κ²Œμ‹œκΈ€ 이미지와 μ—°κ²°

@OneToMany(mappedBy = "post", cascade = CascadeType.ALL, orphanRemoval = true)
private List<PostImage> postImages; // βœ… κ²Œμ‹œκΈ€ 이미지와 μ—°κ²°
@Builder.Default
private List<Recommend> recommends = new ArrayList<>();

// 쑰회수 증가
public void incrementViewCnt() {
this.viewCnt++;
}

// μΆ”μ²œμˆ˜ 증가
public void incrementRecommendCnt() {
this.recommendCnt++;
}

// μΆ”μ²œμˆ˜ κ°μ†Œ
public void decrementRecommendCnt() {
this.recommendCnt = Math.max(0, this.recommendCnt - 1);
}

public void incrementCommentCnt() {
this.commentCnt++;
}

public void decrementCommentCnt() {
this.commentCnt = Math.max(0, this.commentCnt - 1);
}
}
20 changes: 18 additions & 2 deletions src/main/java/com/hyetaekon/hyetaekon/post/entity/PostImage.java
Original file line number Diff line number Diff line change
@@ -1,12 +1,16 @@
package com.hyetaekon.hyetaekon.post.entity;

import jakarta.persistence.*;
import lombok.Getter;
import lombok.Setter;
import lombok.*;

import java.time.LocalDateTime;

@Entity
@Getter
@Setter
@Builder
@NoArgsConstructor
@AllArgsConstructor
public class PostImage {

@Id
Expand All @@ -19,4 +23,16 @@ public class PostImage {

@Column(name = "image_url", length = 255)
private String imageUrl;

private LocalDateTime deletedAt;

// 이미지가 μ‚­μ œλ˜μ—ˆλŠ”μ§€ ν™•μΈν•˜λŠ” λ©”μ†Œλ“œ
public boolean isDeleted() {
return deletedAt != null;
}

// Soft delete 처리 λ©”μ†Œλ“œ
public void softDelete() {
this.deletedAt = LocalDateTime.now();
}
}
15 changes: 12 additions & 3 deletions src/main/java/com/hyetaekon/hyetaekon/post/entity/PostType.java
Original file line number Diff line number Diff line change
@@ -1,7 +1,16 @@
package com.hyetaekon.hyetaekon.post.entity;

import com.fasterxml.jackson.annotation.JsonValue;
import lombok.AllArgsConstructor;
import lombok.Getter;

@Getter
@AllArgsConstructor
public enum PostType {
QUESTION, // 질문 κ²Œμ‹œνŒ
FREE, // 자유 κ²Œμ‹œνŒ
GREETING // 인사 κ²Œμ‹œνŒ
QUESTION("질문"),
FREE("자유"),
GREETING("인사");

@JsonValue
private final String koreanName;
}
Loading