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
@@ -0,0 +1,33 @@
package org.fontory.fontorybe.config;

import com.fasterxml.jackson.databind.ObjectMapper;
import java.lang.reflect.Type;
import org.springframework.http.MediaType;
import org.springframework.http.converter.json.AbstractJackson2HttpMessageConverter;
import org.springframework.stereotype.Component;

/**
* For Swagger to use RequestPart and dto
*/
@Component
public class OctetStreamReadMessageConverter extends AbstractJackson2HttpMessageConverter {

public OctetStreamReadMessageConverter(ObjectMapper objectMapper) {
super(objectMapper, MediaType.APPLICATION_OCTET_STREAM);
}

@Override
public boolean canWrite(Class<?> clazz, MediaType mediaType) {
return false;
}

@Override
public boolean canWrite(Type type, Class<?> clazz, MediaType mediaType) {
return false;
}

@Override
protected boolean canWrite(MediaType mediaType) {
return false;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,20 @@ public FileCreate toProfileImageFileCreate(MultipartFile file, Long memberId) {
.build();
}

public FileCreate toFontTemplateImageFileCreate(MultipartFile file, Long memberId) {
Member foundMember = memberService.getOrThrowById(memberId);
Provide provide = provideService.getOrThrownById(foundMember.getProvideId());

validateImageFile(file);
String generatedFileName = generateFileName(file, provide);

return FileCreate.builder()
.file(file)
.fileType(FileType.FONT_PAPER)
.fileName(generatedFileName)
.build();
}

private void validateImageFile(MultipartFile file) {
if (file == null || file.isEmpty()) {
throw new FileEmptyException("File is empty.");
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -50,4 +50,22 @@ private void deleteLastImages(String fileName) {
s3Template.deleteObject(profileImageBucketName,fileNameWithoutExtension + ".jpeg");
s3Template.deleteObject(profileImageBucketName,fileNameWithoutExtension + ".png");
}

@Override
public FileMetadata uploadFontTemplateImage(FileCreate request) {
AmazonS3PutRequest amazonS3PutRequest = AmazonS3PutRequest.from(request, clockHolder.getCurrentTimeStamp());

try (InputStream inputStream = amazonS3PutRequest.getFile().getInputStream()) {
S3Resource s3Resource = s3Template.upload(
fontPaperBucketName,
amazonS3PutRequest.getKey(),
inputStream);

String objectUrl = s3Resource.getURL().toExternalForm();

return AmazonS3ObjectMetadata.from(amazonS3PutRequest, objectUrl).toModel();
} catch (IOException e) {
throw new RuntimeException(e);
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -6,4 +6,6 @@
public interface CloudStorageService {

FileMetadata uploadProfileImage(FileCreate fileCreate);

FileMetadata uploadFontTemplateImage(FileCreate fileCreate);
}
Original file line number Diff line number Diff line change
Expand Up @@ -6,4 +6,6 @@
public interface FileService {

FileDetails uploadProfileImage(FileCreate fileCreate);

FileDetails uploadFontTemplateImage(FileCreate fileCreate);
}
Original file line number Diff line number Diff line change
Expand Up @@ -19,4 +19,11 @@ public FileDetails uploadProfileImage(FileCreate fileCreate) {

return FileDetails.from(fileMetadata);
}

@Override
public FileDetails uploadFontTemplateImage(FileCreate fileCreate) {
FileMetadata fileMetadata = cloudStorageService.uploadFontTemplateImage(fileCreate);

return FileDetails.from(fileMetadata);
}
}
Original file line number Diff line number Diff line change
@@ -1,9 +1,25 @@
package org.fontory.fontorybe.font.controller;

import java.util.List;
import static org.fontory.fontorybe.file.validator.MultipartFileValidator.extractSingleMultipartFile;

import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.Parameter;
import io.swagger.v3.oas.annotations.media.ArraySchema;
import io.swagger.v3.oas.annotations.media.Content;
import io.swagger.v3.oas.annotations.media.Schema;
import io.swagger.v3.oas.annotations.tags.Tag;
import java.util.List;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.fontory.fontorybe.authentication.adapter.inbound.Login;
import org.fontory.fontorybe.authentication.domain.UserPrincipal;
import org.fontory.fontorybe.file.adapter.inbound.FileRequestMapper;
import org.fontory.fontorybe.file.adapter.inbound.dto.FileUploadResponse;
import org.fontory.fontorybe.file.application.FileService;
import org.fontory.fontorybe.file.domain.FileCreate;
import org.fontory.fontorybe.file.domain.FileDetails;
import org.fontory.fontorybe.font.controller.dto.FontCreateDTO;
import org.fontory.fontorybe.font.controller.dto.FontCreateResponse;
import org.fontory.fontorybe.font.controller.dto.FontDeleteResponse;
Expand All @@ -18,26 +34,21 @@
import org.fontory.fontorybe.font.domain.Font;
import org.springframework.data.domain.Page;
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.DeleteMapping;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.ModelAttribute;
import org.springframework.web.bind.annotation.PatchMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.PutMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RequestPart;
import org.springframework.web.bind.annotation.RestController;

import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;

import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.Parameter;
import io.swagger.v3.oas.annotations.tags.Tag;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.web.multipart.MultipartFile;

@Slf4j
@Tag(name = "폰트 관리", description = "폰트 API")
Expand All @@ -46,7 +57,9 @@
@RequiredArgsConstructor
public class FontController {
private final FontService fontService;
private final FileService fileService;
private final ObjectMapper objectMapper;
private final FileRequestMapper fileRequestMapper;

/**
* Convert an object to JSON string for logging
Expand All @@ -62,19 +75,53 @@ private String toJson(Object obj) {
}

@Operation(summary = "폰트 생성")
@PostMapping
public ResponseEntity<?> addFont(@RequestBody FontCreateDTO fontCreateDTO, @Login UserPrincipal userPrincipal) {
@PostMapping(consumes = MediaType.MULTIPART_FORM_DATA_VALUE)
public ResponseEntity<?> addFont(
@Login UserPrincipal userPrincipal,
@RequestPart("fontCreateDTO") FontCreateDTO fontCreateDTO,
@Parameter(
description = "업로드할 파일. 정확히 1개의 파일만 제공되어야 합니다.",
required = true,
content = @Content(
mediaType = MediaType.MULTIPART_FORM_DATA_VALUE,
array = @ArraySchema(
schema = @Schema(type = "string", format = "binary"),
maxItems = 1
)
)
)
@RequestPart("file") List<MultipartFile> files
) {
Long memberId = userPrincipal.getId();
log.info("Request received: Create font for member ID: {}, request: {}",

MultipartFile file = extractSingleMultipartFile(files);

log.info("Request received: Create font and Upload font template image for member ID: {}, request: {}",
memberId, toJson(fontCreateDTO));

Font createdFont = fontService.create(memberId, fontCreateDTO);
log.info("Response sent: Font created with ID: {}, name: {}",
createdFont.getId(), createdFont.getName());
logFileDetails(file, "Font template image upload");

FileCreate fileCreate = fileRequestMapper.toFontTemplateImageFileCreate(file, memberId);
FileDetails fileDetails = fileService.uploadFontTemplateImage(fileCreate);
FileUploadResponse fileUploadResponse = FileUploadResponse.from(fileDetails);

Font createdFont = fontService.create(memberId, fontCreateDTO, fileDetails);

log.info("Response sent: Font created with ID: {}, name: {} and Font template image uploaded successfully, url: {}, fileName: {}, size: {} bytes",
createdFont.getId(), createdFont.getName(), fileDetails.getFileUrl(), fileDetails.getFileName(), fileDetails.getSize());

return ResponseEntity
.status(HttpStatus.CREATED)
.body(FontCreateResponse.from(createdFont));
.body(FontCreateResponse.from(createdFont, fileUploadResponse));
}

private void logFileDetails(MultipartFile file, String context) {
log.debug("{} - File details: name='{}', original name='{}', size={} bytes, contentType='{}'",
context,
file.getName(),
file.getOriginalFilename(),
file.getSize(),
file.getContentType());
}

@Operation(summary = "폰트 제작 상황")
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
import java.time.LocalDateTime;
import lombok.Builder;
import lombok.Getter;
import org.fontory.fontorybe.file.adapter.inbound.dto.FileUploadResponse;
import org.fontory.fontorybe.font.domain.Font;
import org.fontory.fontorybe.font.infrastructure.entity.FontStatus;

Expand All @@ -14,14 +15,16 @@ public class FontCreateResponse {
private FontStatus status;
private Long memberId;
private LocalDateTime createdAt;
private FileUploadResponse fileUploadResponse;

public static FontCreateResponse from(Font font) {
public static FontCreateResponse from(Font font, FileUploadResponse fileUploadResponse) {
return FontCreateResponse.builder()
.id(font.getId())
.name(font.getName())
.status(font.getStatus())
.memberId(font.getMemberId())
.createdAt(font.getCreatedAt())
.fileUploadResponse(fileUploadResponse)
.build();
}
}
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package org.fontory.fontorybe.font.controller.port;

import java.util.List;
import org.fontory.fontorybe.file.domain.FileDetails;
import org.fontory.fontorybe.font.controller.dto.FontCreateDTO;
import org.fontory.fontorybe.font.controller.dto.FontDeleteResponse;
import org.fontory.fontorybe.font.controller.dto.FontDetailResponse;
Expand All @@ -13,7 +14,7 @@
import org.springframework.data.domain.Page;

public interface FontService {
Font create(Long memberId, FontCreateDTO fontCreateDTO);
Font create(Long memberId, FontCreateDTO fontCreateDTO, FileDetails fileDetails);
List<FontProgressResponse> getFontProgress(Long memberId);
Font update(Long memberId, Long fontId, FontUpdateDTO fontUpdateDTO);
Font getOrThrowById(Long id);
Expand Down
8 changes: 7 additions & 1 deletion src/main/java/org/fontory/fontorybe/font/domain/Font.java
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
import lombok.Builder;
import lombok.Getter;
import lombok.NoArgsConstructor;
import org.fontory.fontorybe.file.domain.FileDetails;
import org.fontory.fontorybe.font.controller.dto.FontCreateDTO;
import org.fontory.fontorybe.font.controller.dto.FontProgressUpdateDTO;
import org.fontory.fontorybe.font.controller.dto.FontUpdateDTO;
Expand Down Expand Up @@ -35,6 +36,8 @@ public class Font {

private Long memberId;

private String templateURL;

private LocalDateTime createdAt;

private LocalDateTime updatedAt;
Expand All @@ -51,14 +54,15 @@ public void increaseDownloadCount() {
this.downloadCount++;
}

public static Font from(FontCreateDTO fontCreateDTO, Long memberId) {
public static Font from(FontCreateDTO fontCreateDTO, Long memberId, FileDetails fileDetails) {
return Font.builder()
.name(fontCreateDTO.getName())
.status(FontStatus.PROGRESS)
.example(fontCreateDTO.getExample())
.downloadCount(0L)
.bookmarkCount(0L)
.memberId(memberId)
.templateURL(fileDetails.getFileUrl())
.build();
}

Expand All @@ -73,6 +77,7 @@ public Font update(FontUpdateDTO fontUpdateDTO) {
.ttf(this.ttf)
.woff(this.woff)
.memberId(this.memberId)
.templateURL(this.templateURL)
.createdAt(this.createdAt)
.updatedAt(this.updatedAt)
.build();
Expand All @@ -89,6 +94,7 @@ public Font updateProgress(FontProgressUpdateDTO fontProgressUpdateDTO) {
.ttf(this.ttf)
.woff(this.woff)
.memberId(this.memberId)
.templateURL(this.templateURL)
.createdAt(this.createdAt)
.updatedAt(this.updatedAt)
.build();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,8 @@ public class FontEntity extends BaseEntity {

private Long memberId;

private String templateURL;

public Font toModel() {
return Font.builder()
.id(id)
Expand All @@ -57,6 +59,7 @@ public Font toModel() {
.ttf(ttf)
.woff(woff)
.memberId(memberId)
.templateURL(templateURL)
.createdAt(getCreatedAt())
.updatedAt(getUpdatedAt())
.build();
Expand All @@ -73,6 +76,7 @@ public static FontEntity from(Font font) {
.ttf(font.getTtf())
.woff(font.getWoff())
.memberId(font.getMemberId())
.templateURL(font.getTemplateURL())
.createdAt(font.getCreatedAt())
.updatedAt(font.getUpdatedAt())
.build();
Expand Down
Loading