Skip to content
Original file line number Diff line number Diff line change
Expand Up @@ -18,8 +18,8 @@ public class PostAdminFacade {
private final PostQueryService postQueryService;
private final PostSchedulingService postSchedulingService;

public PostPersistResponse createPost(PostRequest request) {
Long id = postCommandService.createPost(request.title(), request.content(), request.category());
public PostPersistResponse createPost(Long fileId, PostRequest request) {
Long id = postCommandService.createPost(request.title(), request.content(), request.category(), fileId);
return PostPersistResponse.from(id);
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
import jakarta.validation.constraints.Positive;
import kgu.developers.admin.post.presentation.request.PostRequest;
import kgu.developers.admin.post.presentation.response.PostPersistResponse;
import org.springframework.web.bind.annotation.RequestParam;

@Tag(name = "Post", description = "게시글 관리자 API")
public interface PostAdminController {
Expand All @@ -27,6 +28,10 @@ public interface PostAdminController {
responseCode = "201",
content = @Content(schema = @Schema(implementation = PostPersistResponse.class)))
ResponseEntity<PostPersistResponse> createPost(
@Parameter(
description = "게시글에 저장할 파일의 ID 입니다.",
example = "1"
) @RequestParam(required = false, defaultValue = "0") Long fileId,
@Parameter(
description = "게시글 생성 request 객체 입니다.",
required = true
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,11 @@
package kgu.developers.admin.post.presentation;

import static org.springframework.http.HttpStatus.CREATED;

import jakarta.validation.Valid;
import jakarta.validation.constraints.Positive;
import kgu.developers.admin.post.application.PostAdminFacade;
import kgu.developers.admin.post.presentation.request.PostRequest;
import kgu.developers.admin.post.presentation.response.PostPersistResponse;
import lombok.RequiredArgsConstructor;
import org.springframework.http.ResponseEntity;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.web.bind.annotation.GetMapping;
Expand All @@ -10,14 +14,10 @@
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.RequestParam;
import org.springframework.web.bind.annotation.RestController;

import jakarta.validation.Valid;
import jakarta.validation.constraints.Positive;
import kgu.developers.admin.post.application.PostAdminFacade;
import kgu.developers.admin.post.presentation.request.PostRequest;
import kgu.developers.admin.post.presentation.response.PostPersistResponse;
import lombok.RequiredArgsConstructor;
import static org.springframework.http.HttpStatus.CREATED;

@RestController
@RequiredArgsConstructor
Expand All @@ -29,9 +29,10 @@ public class PostAdminControllerImpl implements PostAdminController {
@Override
@PostMapping
public ResponseEntity<PostPersistResponse> createPost(
@RequestParam(required = false, defaultValue = "0") Long fileId,
@Valid @RequestBody PostRequest request
) {
PostPersistResponse response = postAdminFacade.createPost(request);
PostPersistResponse response = postAdminFacade.createPost(fileId, request);
return ResponseEntity.status(CREATED).body(response);
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ public record PostRequest(
@NotBlank
String content,

@Schema(description = "게시물 카테고리", example = "DEPT_INFO", requiredMode = NOT_REQUIRED)
@Schema(description = "게시물 카테고리", example = "NOTIFICATION", requiredMode = NOT_REQUIRED)
Category category
) {
}
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,8 @@
import static org.junit.jupiter.api.Assertions.assertNotEquals;
import static org.junit.jupiter.api.Assertions.assertNull;

import kgu.developers.domain.file.application.query.FileQueryService;
import mock.repository.FakeFileRepository;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Test;
Expand Down Expand Up @@ -36,9 +38,11 @@ public class PostAdminFacadeTest {
public void init() {
fakePostRepository = new FakePostRepository();
FakeUserRepository fakeUserRepository = new FakeUserRepository();
FakeFileRepository fakeFileRepository = new FakeFileRepository();
UserQueryService userQueryService = new UserQueryService(fakeUserRepository);
FileQueryService fileQueryService = new FileQueryService(fakeFileRepository);
this.postAdminFacade = new PostAdminFacade(
new PostCommandService(userQueryService, fakePostRepository),
new PostCommandService(userQueryService, fakePostRepository, fileQueryService),
new PostQueryService(fakePostRepository),
new PostSchedulingService(fakePostRepository)
);
Expand All @@ -60,7 +64,7 @@ public void init() {

fakePostRepository.save(
Post.create(
"post title", "post content", NOTIFICATION, author
"post title", "post content", NOTIFICATION, author, null
)
);
}
Expand All @@ -74,9 +78,10 @@ void createPost_Success() {
.content("new content")
.category(NOTIFICATION)
.build();
Long fileId = 1L;

// when
PostPersistResponse post = postAdminFacade.createPost(postRequest);
PostPersistResponse post = postAdminFacade.createPost(fileId, postRequest);
Post found = fakePostRepository.findByIdAndDeletedAtIsNull(post.postId()).get();

// then
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,8 +14,10 @@ public record PostSummaryPageResponse<T>(
@Schema(description = "게시글 정보 리스트",
example = "[{"
+ "\"postId\": 3, "
+ "\"category\": \"공지사항\", "
+ "\"title\": \"SW 부트캠프 4기 교육생 모집\", "
+ "\"author\": \"홈피관리자\", "
+ "\"description\": \"2024학년도 학과 소개가 아래와 같은 일정으로 진행됩\", "
+ "\"views\": 19, "
+ "\"hasAttachment\": false, "
+ "\"isPinned\": false, "
Expand Down
Original file line number Diff line number Diff line change
@@ -1,14 +1,13 @@
package kgu.developers.api.post.presentation.response;

import static io.swagger.v3.oas.annotations.media.Schema.RequiredMode.REQUIRED;

import java.time.format.DateTimeFormatter;

import org.springframework.format.annotation.DateTimeFormat;

import io.swagger.v3.oas.annotations.media.Schema;
import kgu.developers.domain.post.domain.Post;
import lombok.Builder;
import org.springframework.format.annotation.DateTimeFormat;

import java.time.format.DateTimeFormatter;

import static io.swagger.v3.oas.annotations.media.Schema.RequiredMode.REQUIRED;

@Builder
public record PostSummaryResponse(
Expand All @@ -24,6 +23,9 @@ public record PostSummaryResponse(
@Schema(description = "작성자 이름", example = "홈피관리자", requiredMode = REQUIRED)
String author,

@Schema(description = "게시글 내용 앞부분 30자", example = "2024학년도 학과 소개가 아래와 같은 일정으로 진행됩", requiredMode = REQUIRED)
String description,

@Schema(description = "조회수", example = "19", requiredMode = REQUIRED)
int views,

Expand All @@ -39,11 +41,20 @@ public record PostSummaryResponse(
) {
public static PostSummaryResponse from(Post post) {
DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd");

String description;
try {
description = post.getContent().substring(0, 30);
} catch (StringIndexOutOfBoundsException e) {
description = post.getContent();
}

return PostSummaryResponse.builder()
.postId(post.getId())
.category(post.getCategory().getDescription())
.title(post.getTitle())
.author(post.getAuthor().getName())
.description(description)
.views(post.getViews())
.hasAttachment(false) // TODO : 첨부파일 여부 확인
.isPinned(post.isPinned())
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,7 @@ public void init() {
.build());

Post post = fakePostRepository.save(Post.create(
"테스트용 제목1", "테스트용 내용1", NEWS, author
"테스트용 제목1", "테스트용 내용1", NEWS, author, null
));

fakeCommentRepository.save(Comment.create(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,8 @@

import java.util.List;

import kgu.developers.domain.file.application.query.FileQueryService;
import mock.repository.FakeFileRepository;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Test;
Expand Down Expand Up @@ -39,11 +41,13 @@ public class PostFacadeTest {
public void init() {
FakePostRepository fakePostRepository = new FakePostRepository();
FakeUserRepository fakeUserRepository = new FakeUserRepository();
FakeFileRepository fakeFileRepository = new FakeFileRepository();

UserQueryService userQueryService = new UserQueryService(fakeUserRepository);
FileQueryService fileQueryService = new FileQueryService(fakeFileRepository);

postFacade = new PostFacade(
new PostCommandService(userQueryService, fakePostRepository),
new PostCommandService(userQueryService, fakePostRepository, fileQueryService),
new PostQueryService(fakePostRepository)
);

Expand All @@ -63,16 +67,16 @@ public void init() {
);

fakePostRepository.save(Post.create(
"first title", "first content", NEWS, author
"first title", "first content", NEWS, author, null
));

Post delete = fakePostRepository.save(Post.create(
"second title", "second content", NEWS, author
"second title", "second content", NEWS, author, null
));
delete.delete();

fakePostRepository.save(Post.create(
"third title", "third content", NEWS, author
"third title", "third content", NEWS, author, null
));
}

Expand Down
Original file line number Diff line number Diff line change
@@ -1,23 +1,33 @@
package kgu.developers.domain.post.application.command;

import org.springframework.stereotype.Service;

import kgu.developers.domain.file.application.query.FileQueryService;
import kgu.developers.domain.file.domain.FileEntity;
import kgu.developers.domain.file.exception.FileNotFoundException;
import kgu.developers.domain.post.domain.Category;
import kgu.developers.domain.post.domain.Post;
import kgu.developers.domain.post.domain.PostRepository;
import kgu.developers.domain.user.application.query.UserQueryService;
import kgu.developers.domain.user.domain.User;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Service;

@Service
@RequiredArgsConstructor
public class PostCommandService {
private final UserQueryService userQueryService;
private final PostRepository postRepository;
private final FileQueryService fileQueryService;

public Long createPost(String title, String content, Category category) {
public Long createPost(String title, String content, Category category, Long fileId) {
User author = userQueryService.me();
Post post = Post.create(title, content, category, author);

FileEntity file = null;
try {
file = fileQueryService.getFileById(fileId);

Check warning on line 26 in aics-domain/src/main/java/kgu/developers/domain/post/application/command/PostCommandService.java

View check run for this annotation

Codecov / codecov/patch

aics-domain/src/main/java/kgu/developers/domain/post/application/command/PostCommandService.java#L26

Added line #L26 was not covered by tests
} catch (FileNotFoundException ignored) {
}

Check warning on line 28 in aics-domain/src/main/java/kgu/developers/domain/post/application/command/PostCommandService.java

View check run for this annotation

Codecov / codecov/patch

aics-domain/src/main/java/kgu/developers/domain/post/application/command/PostCommandService.java#L28

Added line #L28 was not covered by tests
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion

예외 처리 로직 개선 필요

빈 catch 블록은 잠재적인 문제를 숨길 수 있습니다. 파일을 찾을 수 없는 경우에 대한 처리를 명확히 하는 것이 좋습니다.

다음과 같이 개선을 제안합니다:

 FileEntity file = null;
 try {
-    file = fileQueryService.getFileById(fileId);
+    file = (fileId != null && fileId > 0) ? fileQueryService.getFileById(fileId) : null;
 } catch (FileNotFoundException e) {
-    
+    // 로그 추가
+    log.debug("File not found for ID: {}. Creating post without file.", fileId);
 }
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
FileEntity file = null;
try {
file = fileQueryService.getFileById(fileId);
} catch (FileNotFoundException ignored) {
}
FileEntity file = null;
try {
file = (fileId != null && fileId > 0) ? fileQueryService.getFileById(fileId) : null;
} catch (FileNotFoundException e) {
// 로그 추가
log.debug("File not found for ID: {}. Creating post without file.", fileId);
}


Post post = Post.create(title, content, category, author, file);
return postRepository.save(post).getId();
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -65,14 +65,15 @@ public class Post extends BaseTimeEntity {
@OneToMany(mappedBy = "post", fetch = LAZY, cascade = ALL, orphanRemoval = true)
private List<Comment> comments = new ArrayList<>();

public static Post create(String title, String content, Category category, User author) {
public static Post create(String title, String content, Category category, User author, FileEntity file) {
return Post.builder()
.title(title)
.content(content)
.views(0)
.isPinned(false)
.category(category)
.author(author) // NOTE: User Setter 주입 방지 위해 생성자 주입
.file(file)
.build();
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -43,19 +43,19 @@ public void init() {
}

private static void saveTestUserAndPost(FakeUserRepository fakeUserRepository,
FakePostRepository fakePostRepository) {
FakePostRepository fakePostRepository) {
fakeUserRepository.save(
User.create(TEST_USER_ID, "password1234", "홍길동", "honggildong@kyonggi.ac.kr",
"010-1234-5678", CSE)
);
fakePostRepository.save(Post.create(
"SW 부트캠프 4기 교육생 모집", "SW전문인재양성사업단에서는 SW부트캠프 4기 교육생을 모집합니다.", NEWS,
User.builder().build()
User.builder().build(), null
));
}

private void initializeCommentCommandService(FakePostRepository fakePostRepository,
UserQueryService userQueryService) {
UserQueryService userQueryService) {
commentCommandService = new CommentCommandService(
new PostQueryService(fakePostRepository),
userQueryService,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,7 @@ private static void saveTestComment(FakeCommentRepository fakeCommentRepository,
private static Post saveTestPost() {
FakePostRepository fakePostRepository = new FakePostRepository();
Post commentedPost = Post.create("SW 부트캠프 4기 교육생 모집",
"SW전문인재양성사업단에서는 SW부트캠프 4기 교육생을 모집합니다.", NEWS, User.builder().build());
"SW전문인재양성사업단에서는 SW부트캠프 4기 교육생을 모집합니다.", NEWS, User.builder().build(), null);
return fakePostRepository.save(commentedPost);
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,8 @@ private Post getPost(User author) {
"title",
"content.",
NEWS,
author
author,
null
);
}

Expand Down
28 changes: 13 additions & 15 deletions aics-domain/src/testFixtures/java/mock/FakeTestContainer.java
Original file line number Diff line number Diff line change
@@ -1,17 +1,5 @@
package mock;

import static kgu.developers.domain.user.domain.Major.CSE;

import java.util.HashMap;
import java.util.Map;
import java.util.function.Supplier;

import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.context.SecurityContext;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;

import kgu.developers.domain.about.application.command.AboutCommandService;
import kgu.developers.domain.about.application.query.AboutQueryService;
import kgu.developers.domain.about.domain.AboutRepository;
Expand All @@ -22,7 +10,6 @@
import kgu.developers.domain.comment.application.query.CommentQueryService;
import kgu.developers.domain.comment.domain.CommentRepository;
import kgu.developers.domain.file.application.query.FileQueryService;
import kgu.developers.domain.file.domain.FileRepository;
import kgu.developers.domain.lab.application.command.LabCommandService;
import kgu.developers.domain.lab.application.query.LabQueryService;
import kgu.developers.domain.lab.domain.LabRepository;
Expand All @@ -45,6 +32,17 @@
import mock.repository.FakeProfessorRepository;
import mock.repository.FakeRefreshTokenRepository;
import mock.repository.FakeUserRepository;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.context.SecurityContext;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;

import java.util.HashMap;
import java.util.Map;
import java.util.function.Supplier;

import static kgu.developers.domain.user.domain.Major.CSE;

public class FakeTestContainer {
private final Map<Class<?>, Supplier<?>> suppliers = new HashMap<>();
Expand Down Expand Up @@ -74,7 +72,7 @@ public FakeTestContainer() {
suppliers.put(PostRepository.class, FakePostRepository::new);
suppliers.put(PostQueryService.class, () -> new PostQueryService(get(PostRepository.class)));
suppliers.put(PostCommandService.class,
() -> new PostCommandService(get(UserQueryService.class), get(PostRepository.class)));
() -> new PostCommandService(get(UserQueryService.class), get(PostRepository.class), get(FileQueryService.class)));

suppliers.put(CommentRepository.class, FakeCommentRepository::new);
suppliers.put(CommentQueryService.class, () -> new CommentQueryService(get(CommentRepository.class)));
Expand Down Expand Up @@ -109,6 +107,6 @@ public <T> T get(Class<T> clazz) {
if (!instances.containsKey(clazz)) {
instances.put(clazz, suppliers.get(clazz).get());
}
return (T)instances.get(clazz);
return (T) instances.get(clazz);
}
}
Loading