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 @@ -13,12 +13,11 @@

public record ProblemCreateRequest(


// Map으로 묶여있으니 {} 중괄호 사용
@NotNull(message = "카테고리 이름를 설정해야 합니다.")
@Schema(description = "카테고리 코드 식별자(영어) / 한글 이름", example = "FOR_BEGINNER : 입문자용")
Map<String, String> categories,


@NotBlank(message = "문제 제목을 입력하세요.")
@Schema(description = "제목", example = "A+B")
String title,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@

public record ProblemUpdateRequest(

// 리스트 이므로, [] 대괄호 사용
@Schema(description = "카테고리", example = "FOR_BEGINNER")
List<String> categories,

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@ public class ProblemService {
@Transactional
public void createCategory(CategoryCreateRequest requestDto) {

Category category =problemDomainService.createCategory(requestDto.toCategory());
Category category = problemDomainService.createCategory(requestDto.toCategory());

statUpdateUtil.save(new CategoryStat(category));
}
Expand Down Expand Up @@ -102,7 +102,7 @@ public ProblemDetailResponse getProblem(Long problemId) {

// 문제 수정 ( 관리자 )
@Transactional
public void modifyProblem(Long problemId, ProblemUpdateRequest request) {
public void modifyProblem(Long problemId, ProblemUpdateRequest request, MultipartFile newImage) {

Problem findProblem = problemDomainService.getProblem(problemId);

Expand All @@ -116,6 +116,11 @@ public void modifyProblem(Long problemId, ProblemUpdateRequest request) {
request.reference()
);

// 이미지 수정 처리
if (newImage != null && !newImage.isEmpty()) {
updateProblemImage(findProblem, newImage);
}

problemDomainService.updateCategoryAndSearchEngine(findProblem, request.categories());

}
Expand All @@ -126,6 +131,14 @@ public void removeProblem(Long problemId) {

Problem findProblem = problemDomainService.getProblem(problemId);

// 문제 이미지가 있으면 삭제
if (!findProblem.getImageUrl().isEmpty()) {
for(String fileUrl : findProblem.getImageUrl()) {
s3Uploader.delete(fileUrl);
}
}

// Soft Delete
problemDomainService.removeProblem(findProblem);
}

Expand All @@ -143,5 +156,20 @@ private String uploadImageAfterTransaction(MultipartFile image, Long problemId)
throw new S3Exception(S3ExceptionCode.S3_UPLOAD_FAILED);
}
}

// 이미지 수정
private void updateProblemImage(Problem problem, MultipartFile newImage) {

// 기존 이미지가 있다면 삭제 처리
if (!problem.getImageUrl().isEmpty()) {
for(String fileUrl : problem.getImageUrl()) {
s3Uploader.delete(fileUrl);
}
problem.clearImages();
}

String newImageUrl = uploadImageAfterTransaction(newImage, problem.getId());
problem.addImage(newImageUrl);
}
}

Original file line number Diff line number Diff line change
Expand Up @@ -149,11 +149,17 @@ public void addImage(String image) {
imageUrl.add(image);
}

// 이미지 초기화
public void clearImages() {
this.imageUrl.clear();
}

public void incrementTotalSubmissions() {
totalSubmissions += 1;
}

public void incrementCorrectSubmissions() {
correctSubmissions += 1;

}
}
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ public class S3Uploader {
@Value("${cloud.aws.s3.bucket}")
private String bucket;

// 이미지 업로드
public String upload(MultipartFile multipartFile, String dirName) {
try {
// MIME 타입 검사 (png, jpeg, jpg, webp 만 가능)
Expand Down Expand Up @@ -58,4 +59,22 @@ public String upload(MultipartFile multipartFile, String dirName) {
throw new S3Exception(S3ExceptionCode.S3_UPLOAD_FAILED);
}
}

// 이미지 삭제
public void delete(String fileUrl) {
try {
String fileName = extractKeyFromProblemUrl(fileUrl);
amazonS3.deleteObject(bucket, fileName); // S3 내 이미지 객체 제거.
log.info("S3에서 이미지 삭제 완료: {}", fileName);
} catch (Exception e) {
log.error("S3 이미지 삭제 실패: {}", fileUrl, e);
throw new S3Exception(S3ExceptionCode.S3_DELETE_FAILED);
}
}

// 문제 이미지 URL 가져오기
private String extractKeyFromProblemUrl(String fileUrl) {
// S3 주소 포맷 기준으로 잘라내기
return fileUrl.substring(fileUrl.indexOf("problem/"));
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -10,9 +10,9 @@
@RequiredArgsConstructor
public enum S3ExceptionCode implements ResponseCode {

S3_UPLOAD_FAILED(false, HttpStatus.INTERNAL_SERVER_ERROR, "S3 이미지 업로드 중 오류가 발생했습니다."),
S3_INVALID_FILE_TYPE(false, HttpStatus.BAD_REQUEST, "이미지 파일만 업로드할 수 있습니다.");

S3_UPLOAD_FAILED(false, HttpStatus.INTERNAL_SERVER_ERROR, "S3 이미지 업로드 중 오류가 발생 했습니다."),
S3_INVALID_FILE_TYPE(false, HttpStatus.BAD_REQUEST, "이미지 파일만 업로드할 수 있습니다."),
S3_DELETE_FAILED(false, HttpStatus.INTERNAL_SERVER_ERROR, "S3 이미지 삭제 중 오류가 발생 했습니다.");
private final boolean success;

private final HttpStatus status;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -47,14 +47,15 @@ public ResponseEntity<Void> createProblem(
.build();
}

@PutMapping("/{problemId}")
@PutMapping(path = "/{problemId}", consumes = {MediaType.MULTIPART_FORM_DATA_VALUE})
@Operation(summary = "문제 수정", description = "문제를 수정합니다.")
@ApiResponse(responseCode = "200", description = "문제 수정 성공")
public ResponseEntity<Void> modifyProblem(
@PathVariable Long problemId,
@Valid @RequestBody ProblemUpdateRequest request
@RequestPart @Valid ProblemUpdateRequest request,
@RequestPart(value = "image", required = false) MultipartFile image
) {
problemService.modifyProblem(problemId, request);
problemService.modifyProblem(problemId, request, image);

return ResponseEntity
.status(HttpStatus.OK)
Expand Down