-
Notifications
You must be signed in to change notification settings - Fork 0
Develop #95
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
Develop #95
Changes from all commits
82c5f55
566b405
eef549c
78eb814
2510cf2
fa574df
9c012c2
6b0d13c
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| @@ -0,0 +1,21 @@ | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| package com.example.FixLog.dto.post; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| import lombok.Getter; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| import java.util.List; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| @Getter | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| public class NewPostRequestDto { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| private String postTitle; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| private String coverImageUrl; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| private String problem; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| private String errorMessage; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| private String environment; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| private String reproduceCode; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| private String solutionCode; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| private String causeAnalysis; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| private String referenceLink; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| private String extraContent; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| private List<Long> tags; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
Comment on lines
+8
to
+21
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🛠️ Refactor suggestion DTO 레벨 검증 추가 권장 현재 DTO에 검증 어노테이션이 없어 모든 검증을 서비스 계층에서 수행해야 합니다. +import jakarta.validation.constraints.NotBlank;
+import jakarta.validation.constraints.NotNull;
+import jakarta.validation.constraints.Size;
@Getter
public class NewPostRequestDto {
+ @NotBlank(message = "제목은 필수입니다")
+ @Size(max = 100, message = "제목은 100자 이내여야 합니다")
private String postTitle;
private String coverImageUrl;
+ @NotBlank(message = "문제 설명은 필수입니다")
private String problem;
+ @NotBlank(message = "에러 메시지는 필수입니다")
private String errorMessage;
+ @NotBlank(message = "환경 정보는 필수입니다")
private String environment;
+ @NotBlank(message = "재현 코드는 필수입니다")
private String reproduceCode;
+ @NotBlank(message = "해결 코드는 필수입니다")
private String solutionCode;
private String causeAnalysis;
private String referenceLink;
private String extraContent;
+ @NotNull(message = "태그는 필수입니다")
+ @Size(min = 1, message = "최소 하나의 태그를 선택해야 합니다")
private List<Long> tags;
}📝 Committable suggestion
Suggested change
🤖 Prompt for AI Agents |
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| Original file line number | Diff line number | Diff line change | ||||||||||||||||||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
|
|
@@ -8,6 +8,7 @@ | |||||||||||||||||||||||||||||||||||
| import com.example.FixLog.domain.post.PostTag; | ||||||||||||||||||||||||||||||||||||
| import com.example.FixLog.domain.tag.Tag; | ||||||||||||||||||||||||||||||||||||
| import com.example.FixLog.domain.tag.TagCategory; | ||||||||||||||||||||||||||||||||||||
| import com.example.FixLog.dto.post.NewPostRequestDto; | ||||||||||||||||||||||||||||||||||||
| import com.example.FixLog.dto.post.PostDto; | ||||||||||||||||||||||||||||||||||||
| import com.example.FixLog.dto.post.PostRequestDto; | ||||||||||||||||||||||||||||||||||||
| import com.example.FixLog.dto.post.PostResponseDto; | ||||||||||||||||||||||||||||||||||||
|
|
@@ -62,7 +63,7 @@ public String getDefaultImage(String image){ | |||||||||||||||||||||||||||||||||||
| return imageUrl; | ||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||
| // 게시글 생성하기 | ||||||||||||||||||||||||||||||||||||
| // 게시글 작성하기 | ||||||||||||||||||||||||||||||||||||
| @Transactional | ||||||||||||||||||||||||||||||||||||
| public void createPost(PostRequestDto postRequestDto){ | ||||||||||||||||||||||||||||||||||||
| Member member = memberService.getCurrentMemberInfo(); | ||||||||||||||||||||||||||||||||||||
|
|
@@ -99,18 +100,6 @@ public void createPost(PostRequestDto postRequestDto){ | |||||||||||||||||||||||||||||||||||
| postRepository.save(newPost); | ||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||
| // 이미지 파일 마크다운으로 변경 | ||||||||||||||||||||||||||||||||||||
| public String uploadImage(MultipartFile imageFile){ | ||||||||||||||||||||||||||||||||||||
| SecurityContextHolder.getContext().getAuthentication(); | ||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||
| if (imageFile == null || imageFile.isEmpty()){ | ||||||||||||||||||||||||||||||||||||
| throw new CustomException(ErrorCode.IMAGE_UPLOAD_FAILED); | ||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||
| String imageUrl = s3Service.upload(imageFile, "post-image"); | ||||||||||||||||||||||||||||||||||||
| return ""; | ||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||
| // 태그 다 선택 했는지 | ||||||||||||||||||||||||||||||||||||
| private List<Tag> fetchAndValidateTags(List<Long> tagIds){ | ||||||||||||||||||||||||||||||||||||
| // 태그 ID로 Tag 엔티티 조회 | ||||||||||||||||||||||||||||||||||||
|
|
@@ -160,6 +149,78 @@ private void validatePost(PostRequestDto postRequestDto){ | |||||||||||||||||||||||||||||||||||
| | postRequestDto.getReproduceCode().isBlank() | postRequestDto.getSolutionCode().isBlank()) | ||||||||||||||||||||||||||||||||||||
| throw new CustomException(ErrorCode.REQUIRED_CONTENT_MISSING); | ||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||
| private void validatePost(NewPostRequestDto newPostRequestDto){ | ||||||||||||||||||||||||||||||||||||
| if (newPostRequestDto.getPostTitle().isBlank() | newPostRequestDto.getProblem().isBlank() | ||||||||||||||||||||||||||||||||||||
| | newPostRequestDto.getErrorMessage().isBlank() | newPostRequestDto.getEnvironment().isBlank() | ||||||||||||||||||||||||||||||||||||
| | newPostRequestDto.getReproduceCode().isBlank() | newPostRequestDto.getSolutionCode().isBlank()) | ||||||||||||||||||||||||||||||||||||
| throw new CustomException(ErrorCode.REQUIRED_CONTENT_MISSING); | ||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||
| // 이미지 파일 마크다운으로 변경 | ||||||||||||||||||||||||||||||||||||
| @Transactional | ||||||||||||||||||||||||||||||||||||
| public String uploadImage(MultipartFile imageFile){ | ||||||||||||||||||||||||||||||||||||
| SecurityContextHolder.getContext().getAuthentication(); | ||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||
| if (imageFile == null || imageFile.isEmpty()){ | ||||||||||||||||||||||||||||||||||||
| throw new CustomException(ErrorCode.IMAGE_UPLOAD_FAILED); | ||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||
| String imageUrl = s3Service.upload(imageFile, "post-image"); | ||||||||||||||||||||||||||||||||||||
| return ""; | ||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||
| @Transactional | ||||||||||||||||||||||||||||||||||||
| public void editPost(Long postId, NewPostRequestDto newPostRequestDto) { | ||||||||||||||||||||||||||||||||||||
| Member member = memberService.getCurrentMemberInfo(); | ||||||||||||||||||||||||||||||||||||
| Post post = postRepository.findById(postId) | ||||||||||||||||||||||||||||||||||||
| .orElseThrow(() -> new CustomException(ErrorCode.POST_NOT_FOUND)); | ||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||
|
Comment on lines
+173
to
+177
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 중대한 보안 문제: 작성자 권한 검증 누락 현재 코드는 로그인한 사용자 정보만 가져올 뿐, 게시글 작성자와 비교하지 않습니다. @Transactional
public void editPost(Long postId, NewPostRequestDto newPostRequestDto) {
Member member = memberService.getCurrentMemberInfo();
Post post = postRepository.findById(postId)
.orElseThrow(() -> new CustomException(ErrorCode.POST_NOT_FOUND));
+
+ // 게시글 작성자 확인
+ if (!post.getUserId().equals(member)) {
+ throw new CustomException(ErrorCode.ACCESS_DENIED);
+ }📝 Committable suggestion
Suggested change
🤖 Prompt for AI Agents |
||||||||||||||||||||||||||||||||||||
| // 북마크 카테고리별로 선택 제한 두기 | ||||||||||||||||||||||||||||||||||||
| List<Tag> tags = fetchAndValidateTags(newPostRequestDto.getTags()); | ||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||
| // 아무것도 변경이 없으면 예외처리 | ||||||||||||||||||||||||||||||||||||
| if (Objects.equals(post.getPostTitle(), newPostRequestDto.getPostTitle()) | ||||||||||||||||||||||||||||||||||||
| & Objects.equals(post.getCoverImage(), newPostRequestDto.getCoverImageUrl()) | ||||||||||||||||||||||||||||||||||||
| & Objects.equals(post.getProblem(), newPostRequestDto.getProblem()) | ||||||||||||||||||||||||||||||||||||
| & Objects.equals(post.getErrorMessage(), newPostRequestDto.getErrorMessage()) | ||||||||||||||||||||||||||||||||||||
| & Objects.equals(post.getEnvironment(), newPostRequestDto.getEnvironment()) | ||||||||||||||||||||||||||||||||||||
| & Objects.equals(post.getReproduceCode(), newPostRequestDto.getReproduceCode()) | ||||||||||||||||||||||||||||||||||||
| & Objects.equals(post.getSolutionCode(), newPostRequestDto.getSolutionCode()) | ||||||||||||||||||||||||||||||||||||
| & Objects.equals(post.getCauseAnalysis(), newPostRequestDto.getCauseAnalysis()) | ||||||||||||||||||||||||||||||||||||
| & Objects.equals(post.getReferenceLink(), newPostRequestDto.getReferenceLink()) | ||||||||||||||||||||||||||||||||||||
| & Objects.equals(post.getExtraContent(), newPostRequestDto.getExtraContent()) | ||||||||||||||||||||||||||||||||||||
| & compareTags(post.getPostTags(), tags)){ | ||||||||||||||||||||||||||||||||||||
| throw new CustomException(ErrorCode.NO_CONTENT_CHANGED); | ||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||
| // 필드 업데이트 | ||||||||||||||||||||||||||||||||||||
| post.changeTitle(newPostRequestDto.getPostTitle()); | ||||||||||||||||||||||||||||||||||||
| post.changeCoverImage(newPostRequestDto.getCoverImageUrl()); | ||||||||||||||||||||||||||||||||||||
| post.changeProblem(newPostRequestDto.getProblem()); | ||||||||||||||||||||||||||||||||||||
| post.changeErrorMessage(newPostRequestDto.getErrorMessage()); | ||||||||||||||||||||||||||||||||||||
| post.changeEnvironment(newPostRequestDto.getEnvironment()); | ||||||||||||||||||||||||||||||||||||
| post.changeReproduceCode(newPostRequestDto.getReproduceCode()); | ||||||||||||||||||||||||||||||||||||
| post.changeSolutionCode(newPostRequestDto.getSolutionCode()); | ||||||||||||||||||||||||||||||||||||
| post.changeCauseAnalysis(newPostRequestDto.getCauseAnalysis()); | ||||||||||||||||||||||||||||||||||||
| post.changeReferenceLink(newPostRequestDto.getReferenceLink()); | ||||||||||||||||||||||||||||||||||||
| post.changeExtraContent(newPostRequestDto.getExtraContent()); | ||||||||||||||||||||||||||||||||||||
| post.updateEditedAt(LocalDateTime.now()); | ||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||
| // 태그 저장 | ||||||||||||||||||||||||||||||||||||
| post.clearTags(); // 기존 태그 다 제거 | ||||||||||||||||||||||||||||||||||||
| for (Tag tag : tags) { | ||||||||||||||||||||||||||||||||||||
| PostTag postTag = new PostTag(post, tag); | ||||||||||||||||||||||||||||||||||||
| post.getPostTags().add(postTag); | ||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||
| private boolean compareTags(List<PostTag> currentPostTags, List<Tag> newTags) { | ||||||||||||||||||||||||||||||||||||
| List<Tag> currentTags = currentPostTags.stream() | ||||||||||||||||||||||||||||||||||||
| .map(PostTag::getTagId) | ||||||||||||||||||||||||||||||||||||
| .toList(); | ||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||
| return new HashSet<>(currentTags).equals(new HashSet<>(newTags)); | ||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||
| // 게시글 조회하기 | ||||||||||||||||||||||||||||||||||||
| public PostResponseDto viewPost(Long postId){ | ||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🛠️ Refactor suggestion
필드 검증 로직 추가 권장
현재 setter 메서드들이 검증 없이 값을 직접 설정합니다.
최소한 필수 필드에 대한 null/blank 검증을 추가하는 것이 좋습니다.
public void changeTitle(String newTitle){ + if (newTitle == null || newTitle.isBlank()) { + throw new IllegalArgumentException("제목은 비어있을 수 없습니다"); + } + if (newTitle.length() > 100) { + throw new IllegalArgumentException("제목은 100자를 초과할 수 없습니다"); + } this.postTitle = newTitle; }📝 Committable suggestion
🤖 Prompt for AI Agents