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 @@ -3,6 +3,7 @@
import com.redo.domain.community.converter.CommunityConverter;
import com.redo.domain.community.dto.req.CommunityCommentCreateRequestDTO;
import com.redo.domain.community.dto.req.CommunityCreateRequestDTO;
import com.redo.domain.community.dto.req.CommunityUpdateRequestDTO;
import com.redo.domain.community.dto.res.CommunityCommentCreateResponseDTO;
import com.redo.domain.community.dto.res.CommunityCommentDeleteResponseDTO;
import com.redo.domain.community.dto.res.CommunityCommentListResponseDTO;
Expand All @@ -11,6 +12,7 @@
import com.redo.domain.community.dto.res.CommunityDetailResponseDTO;
import com.redo.domain.community.dto.res.CommunityLikeResponseDTO;
import com.redo.domain.community.dto.res.CommunityPageResponseDTO;
import com.redo.domain.community.dto.res.CommunityUpdateResponseDTO;
import com.redo.domain.community.exception.CommunityException;
import com.redo.domain.community.exception.code.CommunityErrorCode;
import com.redo.domain.community.exception.code.CommunitySuccessCode;
Expand Down Expand Up @@ -99,9 +101,24 @@ public ApiResponse<CommunityCreateResponseDTO> createCommunityPost(
);
}

// 커뮤니티 게시글 수정 API
// 톰캣이 multipart 본문을 파싱하는 메서드가 기본적으로 POST 뿐이라(PUT/PATCH 는 텍스트 필드가 누락된다) POST 로 제공한다.
@PostMapping(value = "/{communityId}", consumes = MediaType.MULTIPART_FORM_DATA_VALUE)
public ApiResponse<CommunityUpdateResponseDTO> updateCommunityPost(
@AuthenticationPrincipal Long userId,
@PathVariable Long communityId,
@Valid @ModelAttribute CommunityUpdateRequestDTO request
) {
return ApiResponse.onSuccess(
CommunitySuccessCode.UPDATE_COMMUNITY_POST_SUCCESS,
communityService.updateCommunityPost(userId, communityId, request)
);
}

// 커뮤니티 게시글 댓글 목록 조회 API
@GetMapping("/{communityId}/comments")
public ApiResponse<CommunityCommentListResponseDTO> getCommunityComments(
@AuthenticationPrincipal Long userId,
@PathVariable Long communityId,
@RequestParam(required = false) Long cursor,
@RequestParam(required = false) Integer length
Expand All @@ -112,7 +129,7 @@ public ApiResponse<CommunityCommentListResponseDTO> getCommunityComments(

return ApiResponse.onSuccess(
CommunitySuccessCode.GET_COMMUNITY_COMMENTS_SUCCESS,
communityService.getCommunityComments(communityId, cursor, length)
communityService.getCommunityComments(userId, communityId, cursor, length)
);
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,9 +7,11 @@
import com.redo.domain.community.dto.res.CommunityCreateResponseDTO;
import com.redo.domain.community.dto.res.CommunityDeleteResponseDTO;
import com.redo.domain.community.dto.res.CommunityDetailResponseDTO;
import com.redo.domain.community.dto.res.CommunityImageResponseDTO;
import com.redo.domain.community.dto.res.CommunityLikeResponseDTO;
import com.redo.domain.community.dto.res.CommunityPageResponseDTO;
import com.redo.domain.community.dto.res.CommunityResponseDTO;
import com.redo.domain.community.dto.res.CommunityUpdateResponseDTO;
import com.redo.domain.community.entity.Community;
import com.redo.domain.community.entity.CommunityComment;
import com.redo.domain.community.entity.CommunityImg;
Expand Down Expand Up @@ -72,7 +74,7 @@ public static CommunityDetailResponseDTO toCommunityDetailResponse(
String writer,
String profileImageUrl,
String characterCode,
List<String> imageUrls,
List<CommunityImageResponseDTO> images,
long numComments,
boolean isLiked,
boolean isMine
Expand All @@ -85,7 +87,8 @@ public static CommunityDetailResponseDTO toCommunityDetailResponse(
characterCode,
community.getContent(),
community.getCreatedAt(),
imageUrls,
images.stream().map(CommunityImageResponseDTO::imageUrl).toList(),
images,
String.valueOf(community.getCategory().getCode()),
numComments,
community.getLikeCount() == null ? 0 : community.getLikeCount(),
Expand Down Expand Up @@ -137,6 +140,25 @@ public static CommunityCreateResponseDTO toCommunityCreateResponse(
);
}

public static CommunityImageResponseDTO toCommunityImageResponse(CommunityImg image, String imageUrl) {
return new CommunityImageResponseDTO(image.getId(), imageUrl);
}

// 수정 응답에는 수정 직후 화면을 바로 갱신할 수 있도록 남아 있는 이미지 전체(id + Presigned URL)를 담는다.
public static CommunityUpdateResponseDTO toCommunityUpdateResponse(
Community community,
List<CommunityImageResponseDTO> images
) {
return new CommunityUpdateResponseDTO(
community.getId(),
community.getTitle(),
community.getContent(),
String.valueOf(community.getCategory().getCode()),
images,
community.getUpdatedAt()
);
}

public static CommunityDeleteResponseDTO toCommunityDeleteResponse(Long communityId) {
return new CommunityDeleteResponseDTO(communityId);
}
Expand All @@ -154,15 +176,17 @@ public static CommunityCommentResponseDTO toCommunityCommentResponse(
CommunityComment comment,
String writer,
String profileImageUrl,
String characterCode
String characterCode,
boolean isMine
) {
return new CommunityCommentResponseDTO(
comment.getId(),
writer,
profileImageUrl,
characterCode,
comment.getContent(),
comment.getCreatedAt()
comment.getCreatedAt(),
isMine
);
}

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
package com.redo.domain.community.dto.req;

import jakarta.validation.constraints.NotBlank;
import jakarta.validation.constraints.NotNull;
import org.springframework.web.multipart.MultipartFile;

import java.util.List;

// 첨부 이미지는 부분 수정한다. deleteImageIds 로 지정한 기존 이미지만 삭제하고, images 로 받은 이미지를 새로 추가한다.
// (둘 다 보내지 않으면 기존 이미지는 그대로 유지된다.)
public record CommunityUpdateRequestDTO(
@NotNull Integer category,
@NotBlank String title,

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo "Locate relevant files"
fd -a 'CommunityUpdateRequestDTO.java|Community.java|CommunityService.java' src/main/java || true

echo
echo "Files with validation annotations around community DTOs"
rg -n "class CommunityUpdateRequest|record CommunityUpdateRequest|`@NotBlank`|`@Size`|CommunityUpdateRequestDTO" src/main/java || true

echo
echo "CommunityUpdateRequestDTO.java"
cat -n src/main/java/com/redo/domain/community/dto/req/CommunityUpdateRequestDTO.java

echo
echo "Community.java relevant fields"
sed -n '1,90p' src/main/java/com/redo/domain/community/entity/Community.java | cat -n

echo
echo "CommunityService.java relevant update/image lines"
sed -n '260,350p' src/main/java/com/redo/domain/community/service/CommunityService.java | cat -n

echo
echo "CommunityService.java validation methods containing CommunityUpdateRequest"
rg -n "CommunityUpdateRequest|`@NotBlank`|`@Size`|editImages|updateCommunity|save|saveAndFlush|validation" src/main/java/com/redo/domain/community/service src/main/java/com/redo/domain/community -g '*.java' || true

Repository: REDO-Team/Back

Length of output: 19062


🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo "CommunityService.java updateCommunityPost and validation helper"
sed -n '70,190p' src/main/java/com/redo/domain/community/service/CommunityService.java | cat -n

echo
echo "CommunityService.java editImages and deleteImages"
sed -n '334,390p' src/main/java/com/redo/domain/community/service/CommunityService.java | cat -n

echo
echo "CommunityController.java updateCommunityPost annotations"
sed -n '95,120p' src/main/java/com/redo/domain/community/controller/CommunityController.java | cat -n

echo
echo "CommunityException and CODE definitions related to title/content"
rg -n "TITLE_REQUIRED|CONTENT_REQUIRED|COMMUNITY_NOT_FOUND|GeneralExceptionAdvice|ErrorCode|`@RestControllerAdvice`|ExceptionHandler" src/main/java -g '*.java' || true

Repository: REDO-Team/Back

Length of output: 50370


수정 API에서 title 길이를 영속화 전에 제한하십시오.

Community.titlelength = 100으로 제한되지만, CommunityUpdateRequestDTO.title은 공백만 검증합니다. 101자 제목 요청은 editImages()의 S3 업로드/삭제 작업 이후 flush에서 실패할 수 있습니다. DTO에 @Size(max = 100)을 적용하고, editImages()CommunityService.validatePostRequest()에도 같은 길이 검증을 추가하십시오.

수정 예시
 import jakarta.validation.constraints.NotBlank;
 import jakarta.validation.constraints.NotNull;
+import jakarta.validation.constraints.Size;

-        `@NotBlank` String title,
+        `@NotBlank` `@Size`(max = 100) String title,
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In
`@src/main/java/com/redo/domain/community/dto/req/CommunityUpdateRequestDTO.java`
at line 13, CommunityUpdateRequestDTO의 title에 `@Size`(max = 100)을 추가하고,
CommunityService의 validatePostRequest()에서 editImages()가 실행되기 전에 동일한 최대 길이 검증을
수행하도록 수정하십시오. Community.title의 100자 제한과 일치시키고, 초과 요청은 S3 작업이나 영속화 전에 거부되도록 기존 검증
흐름을 유지하십시오.

@NotBlank String content,
List<Long> deleteImageIds,
List<MultipartFile> images
) {
}
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
package com.redo.domain.community.dto.res;

import com.fasterxml.jackson.annotation.JsonProperty;

import java.time.LocalDateTime;

public record CommunityCommentResponseDTO(
Expand All @@ -8,6 +10,8 @@ public record CommunityCommentResponseDTO(
String profileImageUrl,
String characterCode,
String content,
LocalDateTime createdAt
LocalDateTime createdAt,
// ApiResponse 의 isSuccess 와 동일하게, Jackson 이 is 접두사를 떼지 않도록 이름을 고정한다.
@JsonProperty("isMine") boolean isMine
) {
}
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,9 @@ public record CommunityDetailResponseDTO(
String characterCode,
String content,
LocalDateTime createdAt,
// imageUrls 는 기존 클라이언트 호환을 위해 유지하고, 수정 시 삭제할 이미지를 지정할 수 있도록 images(id + url)를 함께 내려준다.
List<String> imageUrls,
List<CommunityImageResponseDTO> images,
String category,
Long numComments,
Integer numLikes,
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
package com.redo.domain.community.dto.res;

// 수정 시 삭제할 이미지를 지정할 수 있도록 조회용 Presigned URL 과 이미지 id 를 함께 내려준다.
public record CommunityImageResponseDTO(
Long imageId,
String imageUrl
) {
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
package com.redo.domain.community.dto.res;

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

public record CommunityUpdateResponseDTO(
Long id,
String title,
String content,
String category,
List<CommunityImageResponseDTO> images,
LocalDateTime updatedAt
) {
}
13 changes: 13 additions & 0 deletions src/main/java/com/redo/domain/community/entity/Community.java
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,19 @@ public class Community extends BaseEntity {
@Column(name = "like_count")
private Integer likeCount;

// 게시글 수정: 작성자만 호출하며 카테고리/제목/본문을 갱신한다(첨부 이미지는 별도로 교체한다).
public void update(CommunityCategory category, String title, String content) {
this.category = category;
this.title = title;
this.content = content;
}

// 첨부 이미지만 바뀐 경우처럼 게시글 컬럼 자체는 그대로일 때도 수정 시각을 갱신하기 위해 호출한다.
// (updatedAt 이 바뀌면서 엔티티가 변경 상태가 되어 UPDATE 가 나가고, BaseEntity 의 @PreUpdate 도 동작한다.)
public void touch() {
onUpdate();
}

// 소프트 삭제: 실제 삭제 대신 deletedAt 을 기록해 조회에서 제외한다.
public void softDelete() {
this.deletedAt = LocalDateTime.now();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,11 @@ public enum CommunityErrorCode implements BaseErrorCode {

COMMENT_NOT_FOUND(HttpStatus.NOT_FOUND,
"COMMUNITY_404_002",
"댓글이 존재하지 않습니다.");
"댓글이 존재하지 않습니다."),

COMMUNITY_IMAGE_NOT_FOUND(HttpStatus.NOT_FOUND,
"COMMUNITY_404_003",
"게시글 이미지가 존재하지 않습니다.");

private final HttpStatus httpStatus;
private final String code;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,10 @@ public enum CommunitySuccessCode implements BaseSuccessCode {
"COMMUNITY_200_006",
"좋아요를 취소했습니다."),

UPDATE_COMMUNITY_POST_SUCCESS(HttpStatus.OK,
"COMMUNITY_200_007",
"커뮤니티 게시글 수정에 성공했습니다."),

CREATE_COMMUNITY_POST_SUCCESS(HttpStatus.CREATED,
"COMMUNITY_201_001",
"커뮤니티 게시글 등록에 성공했습니다."),
Expand Down
Loading