Skip to content

Commit 6b0d13c

Browse files
authored
[FEAT] 게시글 수정하기
2 parents dcd2feb + 9c012c2 commit 6b0d13c

File tree

6 files changed

+150
-17
lines changed

6 files changed

+150
-17
lines changed

src/main/java/com/example/FixLog/config/WebConfig.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ public class WebConfig implements WebMvcConfigurer {
1010
@Override
1111
public void addCorsMappings(CorsRegistry registry) {
1212
registry.addMapping("/**") // 모든 경로에 대해
13-
.allowedOriginPatterns("*") // 모든 도메인 허용 (개발용) → 배포 시 정확한 프론트 주소로 수정 권장
13+
.allowedOriginPatterns("https://fixlog.netlify.app", "http://localhost:3000") // 모든 도메인 허용 (개발용) → 배포 시 정확한 프론트 주소로 수정 권장
1414
.allowedMethods("GET", "POST", "PUT", "DELETE", "PATCH", "OPTIONS")
1515
.allowedHeaders("*")
1616
.allowCredentials(true); // 인증정보(쿠키, Authorization) 허용

src/main/java/com/example/FixLog/controller/PostController.java

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
package com.example.FixLog.controller;
22

3+
import com.example.FixLog.dto.post.NewPostRequestDto;
34
import com.example.FixLog.dto.post.PostRequestDto;
45
import com.example.FixLog.dto.Response;
56
import com.example.FixLog.dto.post.PostResponseDto;
@@ -16,30 +17,43 @@ public PostController(PostService postService){
1617
this.postService = postService;
1718
}
1819

20+
// 게시글 작성하기
1921
@PostMapping
2022
public Response<Object> createPost(@RequestBody PostRequestDto postRequestDto){
2123
postService.createPost(postRequestDto);
2224
return Response.success("게시글 작성 성공.", null);
2325
}
2426

27+
// 이미지 마크다운 형식으로 변환하기
2528
@PostMapping("/images")
2629
public Response<String> uploadImage(@RequestPart("imageFile") MultipartFile imageFile){
2730
String markdownImage = postService.uploadImage(imageFile);
2831
return Response.success("이미지 마크다운 형식으로 변환", markdownImage);
2932
}
3033

34+
// 게시글 수정하기
35+
@PatchMapping("/{postId}/edit")
36+
public Response<Object> editPost(@PathVariable("postId") Long postId,
37+
@RequestBody NewPostRequestDto newPostRequestDto){
38+
postService.editPost(postId, newPostRequestDto);
39+
return Response.success("게시글 수정 성공.", null);
40+
}
41+
42+
// 게시글 보기
3143
@GetMapping("/{postId}")
3244
public Response<Object> viewPost(@PathVariable("postId") Long postId){
3345
PostResponseDto viewPost = postService.viewPost(postId);
3446
return Response.success("게시글 조회하기 성공", viewPost);
3547
}
3648

49+
// 좋아요 누르기/취소하기
3750
@PostMapping("/{postId}/like")
3851
public Response<Object> togglePostLike(@PathVariable("postId") Long postId){
3952
String message = postService.togglePostLike(postId);
4053
return Response.success(message, null); // 좋아요 수정하기
4154
}
4255

56+
// 북마크 누르기/취소하기
4357
@PostMapping("/{postId}/bookmark")
4458
public Response<Object> toggleBookmark(@PathVariable("postId") Long postId) {
4559
String message = postService.toggleBookmark(postId);

src/main/java/com/example/FixLog/domain/post/Post.java

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -79,4 +79,41 @@ public class Post {
7979
@OneToMany(mappedBy = "postId", cascade = CascadeType.ALL, orphanRemoval = true)
8080
private List<PostLike> postLikes = new ArrayList<>();
8181

82+
public void clearTags(){
83+
postTags.clear();
84+
}
85+
86+
public void changeTitle(String newTitle){
87+
this.postTitle = newTitle;
88+
}
89+
public void changeCoverImage(String newCoverImage){
90+
this.coverImage=newCoverImage;
91+
}
92+
public void changeProblem(String newProblem){
93+
this.problem = newProblem;
94+
}
95+
public void changeErrorMessage(String newErrorMessage){
96+
this.errorMessage = newErrorMessage;
97+
}
98+
public void changeEnvironment(String newEnvironment){
99+
this.environment = newEnvironment;
100+
}
101+
public void changeReproduceCode(String newReproduceCode){
102+
this.reproduceCode = newReproduceCode;
103+
}
104+
public void changeSolutionCode(String newSolutionCode){
105+
this.solutionCode = newSolutionCode;
106+
}
107+
public void changeCauseAnalysis(String newCauseAnalysis){
108+
this.causeAnalysis = newCauseAnalysis;
109+
}
110+
public void changeReferenceLink(String newReferenceLink){
111+
this.referenceLink = newReferenceLink;
112+
}
113+
public void changeExtraContent(String newExtraContent){
114+
this.extraContent = newExtraContent;
115+
}
116+
public void updateEditedAt(LocalDateTime newLocalDateTime){
117+
this.editedAt = newLocalDateTime;
118+
}
82119
}
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
package com.example.FixLog.dto.post;
2+
3+
import lombok.Getter;
4+
5+
import java.util.List;
6+
7+
@Getter
8+
public class NewPostRequestDto {
9+
private String postTitle;
10+
private String coverImageUrl;
11+
private String problem;
12+
private String errorMessage;
13+
private String environment;
14+
private String reproduceCode;
15+
private String solutionCode;
16+
private String causeAnalysis;
17+
private String referenceLink;
18+
private String extraContent;
19+
20+
private List<Long> tags;
21+
}

src/main/java/com/example/FixLog/exception/ErrorCode.java

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -30,9 +30,9 @@ public enum ErrorCode {
3030
UNAUTHORIZED(HttpStatus.UNAUTHORIZED, "권한이 없습니다."),
3131
INVALID_REQUEST(HttpStatus.BAD_REQUEST, "요청 데이터가 유효하지 않습니다."),
3232
S3_UPLOAD_FAILED(HttpStatus.BAD_REQUEST, "S3 파일 업로드에 실패했습니다."),
33-
IMAGE_UPLOAD_FAILED(HttpStatus.NOT_FOUND, "이미지 파일이 업로드되지 않았습니다."),
34-
LOGOUT_SUCCESS(HttpStatus.OK, "로그아웃이 정상적으로 처리되었습니다.");
33+
IMAGE_UPLOAD_FAILED(HttpStatus.BAD_REQUEST, "이미지 파일이 업로드되지 않았습니다."),
34+
NO_CONTENT_CHANGED(HttpStatus.BAD_REQUEST, "변경된 내용이 없습니다.");
3535

3636
private final HttpStatus status;
3737
private final String message;
38-
}
38+
}

src/main/java/com/example/FixLog/service/PostService.java

Lines changed: 74 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
import com.example.FixLog.domain.post.PostTag;
99
import com.example.FixLog.domain.tag.Tag;
1010
import com.example.FixLog.domain.tag.TagCategory;
11+
import com.example.FixLog.dto.post.NewPostRequestDto;
1112
import com.example.FixLog.dto.post.PostDto;
1213
import com.example.FixLog.dto.post.PostRequestDto;
1314
import com.example.FixLog.dto.post.PostResponseDto;
@@ -62,7 +63,7 @@ public String getDefaultImage(String image){
6263
return imageUrl;
6364
}
6465

65-
// 게시글 생성하기
66+
// 게시글 작성하기
6667
@Transactional
6768
public void createPost(PostRequestDto postRequestDto){
6869
Member member = memberService.getCurrentMemberInfo();
@@ -99,18 +100,6 @@ public void createPost(PostRequestDto postRequestDto){
99100
postRepository.save(newPost);
100101
}
101102

102-
// 이미지 파일 마크다운으로 변경
103-
public String uploadImage(MultipartFile imageFile){
104-
SecurityContextHolder.getContext().getAuthentication();
105-
106-
if (imageFile == null || imageFile.isEmpty()){
107-
throw new CustomException(ErrorCode.IMAGE_UPLOAD_FAILED);
108-
}
109-
110-
String imageUrl = s3Service.upload(imageFile, "post-image");
111-
return "![image](" + imageUrl + ")";
112-
}
113-
114103
// 태그 다 선택 했는지
115104
private List<Tag> fetchAndValidateTags(List<Long> tagIds){
116105
// 태그 ID로 Tag 엔티티 조회
@@ -160,6 +149,78 @@ private void validatePost(PostRequestDto postRequestDto){
160149
| postRequestDto.getReproduceCode().isBlank() | postRequestDto.getSolutionCode().isBlank())
161150
throw new CustomException(ErrorCode.REQUIRED_CONTENT_MISSING);
162151
}
152+
private void validatePost(NewPostRequestDto newPostRequestDto){
153+
if (newPostRequestDto.getPostTitle().isBlank() | newPostRequestDto.getProblem().isBlank()
154+
| newPostRequestDto.getErrorMessage().isBlank() | newPostRequestDto.getEnvironment().isBlank()
155+
| newPostRequestDto.getReproduceCode().isBlank() | newPostRequestDto.getSolutionCode().isBlank())
156+
throw new CustomException(ErrorCode.REQUIRED_CONTENT_MISSING);
157+
}
158+
159+
// 이미지 파일 마크다운으로 변경
160+
@Transactional
161+
public String uploadImage(MultipartFile imageFile){
162+
SecurityContextHolder.getContext().getAuthentication();
163+
164+
if (imageFile == null || imageFile.isEmpty()){
165+
throw new CustomException(ErrorCode.IMAGE_UPLOAD_FAILED);
166+
}
167+
168+
String imageUrl = s3Service.upload(imageFile, "post-image");
169+
return "![image](" + imageUrl + ")";
170+
}
171+
172+
@Transactional
173+
public void editPost(Long postId, NewPostRequestDto newPostRequestDto) {
174+
Member member = memberService.getCurrentMemberInfo();
175+
Post post = postRepository.findById(postId)
176+
.orElseThrow(() -> new CustomException(ErrorCode.POST_NOT_FOUND));
177+
178+
// 북마크 카테고리별로 선택 제한 두기
179+
List<Tag> tags = fetchAndValidateTags(newPostRequestDto.getTags());
180+
181+
// 아무것도 변경이 없으면 예외처리
182+
if (Objects.equals(post.getPostTitle(), newPostRequestDto.getPostTitle())
183+
& Objects.equals(post.getCoverImage(), newPostRequestDto.getCoverImageUrl())
184+
& Objects.equals(post.getProblem(), newPostRequestDto.getProblem())
185+
& Objects.equals(post.getErrorMessage(), newPostRequestDto.getErrorMessage())
186+
& Objects.equals(post.getEnvironment(), newPostRequestDto.getEnvironment())
187+
& Objects.equals(post.getReproduceCode(), newPostRequestDto.getReproduceCode())
188+
& Objects.equals(post.getSolutionCode(), newPostRequestDto.getSolutionCode())
189+
& Objects.equals(post.getCauseAnalysis(), newPostRequestDto.getCauseAnalysis())
190+
& Objects.equals(post.getReferenceLink(), newPostRequestDto.getReferenceLink())
191+
& Objects.equals(post.getExtraContent(), newPostRequestDto.getExtraContent())
192+
& compareTags(post.getPostTags(), tags)){
193+
throw new CustomException(ErrorCode.NO_CONTENT_CHANGED);
194+
}
195+
196+
// 필드 업데이트
197+
post.changeTitle(newPostRequestDto.getPostTitle());
198+
post.changeCoverImage(newPostRequestDto.getCoverImageUrl());
199+
post.changeProblem(newPostRequestDto.getProblem());
200+
post.changeErrorMessage(newPostRequestDto.getErrorMessage());
201+
post.changeEnvironment(newPostRequestDto.getEnvironment());
202+
post.changeReproduceCode(newPostRequestDto.getReproduceCode());
203+
post.changeSolutionCode(newPostRequestDto.getSolutionCode());
204+
post.changeCauseAnalysis(newPostRequestDto.getCauseAnalysis());
205+
post.changeReferenceLink(newPostRequestDto.getReferenceLink());
206+
post.changeExtraContent(newPostRequestDto.getExtraContent());
207+
post.updateEditedAt(LocalDateTime.now());
208+
209+
// 태그 저장
210+
post.clearTags(); // 기존 태그 다 제거
211+
for (Tag tag : tags) {
212+
PostTag postTag = new PostTag(post, tag);
213+
post.getPostTags().add(postTag);
214+
}
215+
}
216+
217+
private boolean compareTags(List<PostTag> currentPostTags, List<Tag> newTags) {
218+
List<Tag> currentTags = currentPostTags.stream()
219+
.map(PostTag::getTagId)
220+
.toList();
221+
222+
return new HashSet<>(currentTags).equals(new HashSet<>(newTags));
223+
}
163224

164225
// 게시글 조회하기
165226
public PostResponseDto viewPost(Long postId){

0 commit comments

Comments
 (0)