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
31 changes: 26 additions & 5 deletions src/main/java/com/creatorhub/constant/CreationThumbnailType.java
Original file line number Diff line number Diff line change
@@ -1,8 +1,29 @@
package com.creatorhub.constant;

public enum CreationThumbnailType {
POSTER, // 포스터형
HORIZONTAL, // 가로형
DERIVED, // 리사이징(파생) 이미지
EXTRA // 리사이징 후 별도로 수정한 이미지
public enum CreationThumbnailType implements ThumbnailType {
POSTER {
@Override
public String resolveSuffix() {
return ThumbnailKeys.POSTER_SUFFIX;
}
},
HORIZONTAL {
@Override
public String resolveSuffix() {
return ThumbnailKeys.HORIZONTAL_SUFFIX;
}
},
DERIVED {
@Override
public String resolveSuffix() {
return null;
}
},
EXTRA {
@Override
public String resolveSuffix() {
return null;
}
}
}

16 changes: 16 additions & 0 deletions src/main/java/com/creatorhub/constant/EpisodeThumbnailType.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
package com.creatorhub.constant;

public enum EpisodeThumbnailType implements ThumbnailType {
EPISODE {
@Override
public String resolveSuffix() {
return ThumbnailKeys.EPISODE_SUFFIX;
}
},
SNS {
@Override
public String resolveSuffix() {
return ThumbnailKeys.SNS_SUFFIX;
}
}
}
2 changes: 1 addition & 1 deletion src/main/java/com/creatorhub/constant/ErrorCode.java
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ public enum ErrorCode {
AUTHENTICATION_FAILED(HttpStatus.UNAUTHORIZED, "A006", "토큰 인증에 실패했습니다."),

// FileObject 관련 에러
FILE_NOT_FOUND(HttpStatus.NOT_FOUND, "F001", "존재하는 파일입니다."),
FILE_NOT_FOUND(HttpStatus.NOT_FOUND, "F001", "존재하지 않는 파일입니다."),
FILE_STATUS_NOT_CORRECT(HttpStatus.CONFLICT, "F002", "파일의 상태가 일치하지 않거나 올바르지 못합니다."),

// 기타 에러
Expand Down
9 changes: 9 additions & 0 deletions src/main/java/com/creatorhub/constant/ThumbnailKeys.java
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,15 @@ public final class ThumbnailKeys {
"_218x120.jpg"
);

// 회차 썸네일
public static final String EPISODE_SUFFIX = "_202x120.jpg";

// 회차 SNS 전용 썸네일
public static final String SNS_SUFFIX = "_600x315.jpg";

// 원고 전용 썸네일
public static final String MANUSCRIPT_SUFFIX = ".jpg";

public static List<String> allSuffixes() {
List<String> all = new ArrayList<>();
all.add(HORIZONTAL_SUFFIX);
Expand Down
6 changes: 6 additions & 0 deletions src/main/java/com/creatorhub/constant/ThumbnailType.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
package com.creatorhub.constant;

public interface ThumbnailType {
String resolveSuffix();
}

Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ public class CreationController {
/**
* 작품등록
*/
@PostMapping("create")
@PostMapping("/create")
public ResponseEntity<Map<String, Object>> createCreation(@Valid @RequestBody CreationRequest req) {
log.info("작품등록 요청 - creatorId={}, title={}, isPublic={}",
req.creatorId(),
Expand Down
50 changes: 50 additions & 0 deletions src/main/java/com/creatorhub/controller/EpisodeController.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
package com.creatorhub.controller;

import com.creatorhub.dto.EpisodeRequest;
import com.creatorhub.dto.EpisodeResponse;
import com.creatorhub.security.auth.CustomUserPrincipal;
import com.creatorhub.service.EpisodeService;
import jakarta.validation.Valid;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.http.ResponseEntity;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.security.core.annotation.AuthenticationPrincipal;
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.RestController;

@RestController
@RequestMapping("/api/episodes")
@RequiredArgsConstructor
@Slf4j
public class EpisodeController {

private final EpisodeService episodeService;

/**
* 회차 등록 + 원고/썸네일 매핑 insert
*/
@PreAuthorize("hasRole('ROLE_CREATOR')")
@PostMapping("/create")
public ResponseEntity<EpisodeResponse> publishEpisode(
@Valid @RequestBody EpisodeRequest req,
@AuthenticationPrincipal CustomUserPrincipal principal
) {

log.info("회차 등록 요청 - memberId={}, creationId={}, episodeNum={}, manuscripts={}, episodeFileObjectId={}, snsFileObjectId={}, isPublic={}, isCommentEnabled={}",
principal.id(),
req.creationId(),
req.episodeNum(),
req.manuscripts().size(),
req.episodeFileObjectId(),
req.snsFileObjectId(),
req.isPublic(),
req.isCommentEnabled()
);

EpisodeResponse res = episodeService.publishEpisode(req, principal.id());
return ResponseEntity.ok(res);
}
}
62 changes: 52 additions & 10 deletions src/main/java/com/creatorhub/controller/FileUploadController.java
Original file line number Diff line number Diff line change
@@ -1,15 +1,17 @@
package com.creatorhub.controller;

import com.creatorhub.dto.FileObjectResponse;
import com.creatorhub.dto.S3PresignedUrlRequest;
import com.creatorhub.dto.S3PresignedUrlResponse;
import com.creatorhub.dto.s3.*;
import com.creatorhub.service.FileObjectService;
import com.creatorhub.service.s3.S3PresignedUploadService;
import jakarta.validation.Valid;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.web.bind.annotation.*;

import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

@RestController
@RequestMapping("/api/files")
Expand All @@ -20,24 +22,64 @@ public class FileUploadController {
private final FileObjectService fileObjectService;

/**
* presigned url 요청
* 작품 썸네일 presigned url 요청
*/
@PostMapping("/presigned-url")
public S3PresignedUrlResponse createPresignedUrl(@RequestBody S3PresignedUrlRequest req) {
log.info("Presigned PUT 요청 - contentType={}, thumbnailType={}, originalFilename={}",
@PostMapping("/creation-thumbnails/presigned")
public ThumbnailPresignedUrlResponse createCreationThumbnailPresignedUrl(@RequestBody CreationThumbnailPresignedRequest req) {
log.info("작품 썸네일 Presigned PUT 요청 - contentType={}, thumbnailType={}, originalFilename={}",
req.contentType(), req.thumbnailType(), req.originalFilename());

return uploadService.generatePresignedPutUrl(req);
}

/**
* fileObject 작품등록시 이미지 상태 변경(INIT -> READY)
* 회차 썸네일 presigned url 요청
*/
@PostMapping("/{fileObjectId}/uploaded")
public void complete(@PathVariable Long fileObjectId) {
fileObjectService.markReady(fileObjectId);
@PostMapping("/episode-thumbnails/presigned")
public ThumbnailPresignedUrlResponse createEpisodeThumbnailPresignedUrl(@RequestBody EpisodeThumbnailPresignedRequest req) {
log.info("회차 썸네일 Presigned PUT 요청 - contentType={}, thumbnailType={}, originalFilename={}",
req.contentType(), req.thumbnailType(), req.originalFilename());

return uploadService.generatePresignedPutUrl(req);
}

/**
* 원고 presigned url 요청
*/
@PostMapping("/manuscripts/presigned")
public ManuscriptPresignedResponse createManuscriptPresignedUrls(
@Valid @RequestBody ManuscriptPresignedRequest req
) {
// contentType 요약
Map<String, Long> contentTypeSummary = req.files().stream()
.collect(Collectors.groupingBy(
ManuscriptFileRequest::contentType,
Collectors.counting()
));

log.info("원고 Presigned PUT 요청 - creationId={}, count={}, contentTypes={}",
req.creationId(), req.files().size(), contentTypeSummary);

return uploadService.generateManuscriptPresignedUrls(req);
}

/**
* fileObject 썸네일 이미지 상태 변경(INIT -> READY)
*/
@PostMapping("/{fileObjectId}/thumbnails/ready")
public void markThumbnailReady(@PathVariable Long fileObjectId) {
fileObjectService.markThumbnailReady(fileObjectId);
}

/**
* fileObject 원고 이미지 상태 변경(INIT -> READY)
*/
@PostMapping("/manuscripts/ready")
public void markManuscriptsReady(@RequestBody @Valid ManuscriptReadyRequest req) {
fileObjectService.markManuscriptsReady(req.fileObjectIds());
}


/**
* fileObject 작품등록시 가로 리사이징 이미지 업로드 상태 확인(폴링용) & file_object insert
*/
Expand Down
37 changes: 37 additions & 0 deletions src/main/java/com/creatorhub/dto/EpisodeRequest.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
package com.creatorhub.dto;

import jakarta.validation.Valid;
import jakarta.validation.constraints.*;

import java.util.List;

public record EpisodeRequest(
@NotNull(message = "creationId가 존재하지 않습니다.")
Long creationId,

@NotNull(message = "episodeNum이 존재하지 않습니다.")
@Min(value = 1, message = "episodeNum은 1 이상이어야 합니다.")
Integer episodeNum,

@NotBlank(message = "title이 존재하지 않습니다.")
@Size(max = 35, message = "title은 35자 이하여야 합니다.")
String title,

@NotBlank(message = "creatorNote가 존재하지 않습니다.")
@Size(max = 100, message = "creatorNote는 100자 이하여야 합니다.")
String creatorNote,

Boolean isCommentEnabled,
Boolean isPublic,

@NotNull(message = "회차 썸네일의 FileObjectId가 존재하지 않습니다.")
Long episodeFileObjectId,

@NotNull(message = "sns 썸네일의 FileObjectId가 존재하지 않습니다.")
Long snsFileObjectId,

@NotEmpty(message = "원고 파일 목록이 비어있습니다.")
@Size(max = 50, message = "원고는 50장 이하여야 합니다.") // 정책값
List<@Valid ManuscriptRegisterItem> manuscripts

) { }
11 changes: 11 additions & 0 deletions src/main/java/com/creatorhub/dto/EpisodeResponse.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
package com.creatorhub.dto;

import java.util.List;

public record EpisodeResponse(
Long episodeId,
Integer episodeNum,
List<Long> manuscriptImageIds,
List<Long> episodeThumbnailIds
) { }

12 changes: 12 additions & 0 deletions src/main/java/com/creatorhub/dto/ManuscriptRegisterItem.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
package com.creatorhub.dto;

import jakarta.validation.constraints.*;

public record ManuscriptRegisterItem(
@NotNull(message = "fileObjectId가 존재하지 않습니다.")
Long fileObjectId,

@NotNull(message = "displayOrder가 존재하지 않습니다.")
@Min(value = 1, message = "displayOrder는 1 이상이어야 합니다.")
Integer displayOrder
) { }
9 changes: 0 additions & 9 deletions src/main/java/com/creatorhub/dto/S3PresignedUrlRequest.java

This file was deleted.

Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
package com.creatorhub.dto.s3;

import com.creatorhub.constant.CreationThumbnailType;
import jakarta.validation.constraints.NotBlank;
import jakarta.validation.constraints.NotNull;

public record CreationThumbnailPresignedRequest(

@NotBlank(message = "콘텐츠 타입이 존재하지 않습니다.")
String contentType,

@NotNull(message = "썸네일 타입이 존재하지 않습니다.")
CreationThumbnailType thumbnailType,

@NotBlank(message = "원본 파일명이 존재하지 않습니다.")
String originalFilename

) implements PresignedPutRequest {
@Override public String resolveSuffix() {
return thumbnailType.resolveSuffix();
}
}

Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
package com.creatorhub.dto.s3;

import com.creatorhub.constant.CreationThumbnailType;
import com.creatorhub.constant.EpisodeThumbnailType;
import jakarta.validation.constraints.NotBlank;
import jakarta.validation.constraints.NotNull;

public record EpisodeThumbnailPresignedRequest(

@NotBlank(message = "콘텐츠 타입이 존재하지 않습니다.")
String contentType,

@NotNull(message = "썸네일 타입이 존재하지 않습니다.")
EpisodeThumbnailType thumbnailType,

@NotBlank(message = "원본 파일명이 존재하지 않습니다.")
String originalFilename

) implements PresignedPutRequest {
@Override public String resolveSuffix() {
return thumbnailType.resolveSuffix();
}
}

17 changes: 17 additions & 0 deletions src/main/java/com/creatorhub/dto/s3/ManuscriptFileRequest.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
package com.creatorhub.dto.s3;

import jakarta.validation.constraints.Min;
import jakarta.validation.constraints.NotBlank;
import jakarta.validation.constraints.NotNull;

public record ManuscriptFileRequest (
@NotNull(message = "displayOrder가 존재하지 않습니다.")
@Min(value = 1, message = "displayOrder는 1 이상이어야 합니다.")
Integer displayOrder,

@NotBlank(message = "콘텐츠 타입이 존재하지 않습니다.")
String contentType,

@NotBlank(message = "원본 파일명이 존재하지 않습니다.")
String originalFilename
){ }
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
package com.creatorhub.dto.s3;

import jakarta.validation.Valid;
import jakarta.validation.constraints.*;
import java.util.List;

public record ManuscriptPresignedRequest(

@NotNull(message = "creatorId가 존재하지 않습니다.")
Long creationId,

@NotEmpty(message = "원고 파일 목록이 비어있습니다.")
@Size(max = 50, message = "원고는 50장 이하여야 합니다.")
List<@Valid ManuscriptFileRequest> files

) { }

Loading