Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
20 commits
Select commit Hold shift + click to select a range
f0cbc37
feat: Font Validation
SiwonHae May 16, 2025
0bb4eec
feat: Member Validation
SiwonHae May 16, 2025
9bbdc55
Merge pull request #45 from team-fontory/feature/validation
SiwonHae May 16, 2025
42c464e
feat: 폰트 영어 이름 추가
SiwonHae May 16, 2025
9ef074d
feat: 폰트 수정 기능 삭제
SiwonHae May 16, 2025
ab558e5
feat: 폰트 이름 정규 표현식 검증 추가
SiwonHae May 16, 2025
4e74a78
feat: Validation Exception Handler
SiwonHae May 16, 2025
9b7f610
chore: Spring Validation
SiwonHae May 16, 2025
823d8b2
feat: 폰트 영어 이름도 비속어 검증하도록 추가
SiwonHae May 16, 2025
541f970
refactor: 폰트 이름 정규표현식에 숫자 허용
SiwonHae May 16, 2025
560fff1
test: 영어 폰트 이름 추가 테스트 반영
SiwonHae May 16, 2025
e444c37
fix bug empty files sent when onboarding & update memebr
tape4 May 16, 2025
8af6375
Merge remote-tracking branch 'origin/develop' into fix/regiseter
tape4 May 16, 2025
7421c46
Merge pull request #47 from team-fontory/fix/regiseter
tape4 May 16, 2025
11da0c6
fix: /member/me with onboarding user return 401 Unauthorized
tape4 May 16, 2025
b536126
Merge pull request #48 from team-fontory/fix/auth
tape4 May 16, 2025
484cb4c
Merge branch 'develop' of https://github.com/font-king/FONTory_BE int…
SiwonHae May 19, 2025
26b86e4
feat: 메세지 큐에 폰트 영어 이름 전달
SiwonHae May 19, 2025
1369941
Merge pull request #46 from team-fontory/feature/font-eng-name
tape4 May 19, 2025
522b692
refactor: remove terms properties in member entity
tape4 May 19, 2025
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
1 change: 1 addition & 0 deletions build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ dependencies {
// Spring Boot Starters:
implementation 'org.springframework.boot:spring-boot-starter-web'
implementation 'org.springframework.boot:spring-boot-starter-data-jpa'
implementation 'org.springframework.boot:spring-boot-starter-validation'

// OAuth2
implementation 'org.springframework.session:spring-session-data-redis'
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
package org.fontory.fontorybe.authentication.domain.exception;

import org.fontory.fontorybe.common.domain.SkipDiscordNotification;

@SkipDiscordNotification
public class AuthenticationRequiredException extends RuntimeException {
public AuthenticationRequiredException() {
super("Authentication required");
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,9 @@
import io.jsonwebtoken.ExpiredJwtException;
import io.jsonwebtoken.JwtException;
import io.jsonwebtoken.MalformedJwtException;
import java.util.stream.Collectors;
import lombok.RequiredArgsConstructor;
import org.fontory.fontorybe.authentication.domain.exception.AuthenticationRequiredException;
import org.fontory.fontorybe.authentication.domain.exception.InvalidRefreshTokenException;
import org.fontory.fontorybe.authentication.domain.exception.TokenNotFoundException;
import org.fontory.fontorybe.bookmark.domain.exception.BookmarkAlreadyException;
Expand All @@ -28,7 +30,9 @@
import org.fontory.fontorybe.member.domain.exception.MemberNotFoundException;
import org.fontory.fontorybe.member.domain.exception.MemberOwnerMismatchException;
import org.fontory.fontorybe.provide.domain.exception.ProvideNotFoundException;
import org.springframework.context.support.DefaultMessageSourceResolvable;
import org.springframework.http.HttpStatus;
import org.springframework.web.bind.MethodArgumentNotValidException;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.ResponseStatus;
import org.springframework.web.bind.annotation.RestControllerAdvice;
Expand All @@ -38,6 +42,16 @@
@RequiredArgsConstructor
public class GlobalExceptionHandler {

@ExceptionHandler(MethodArgumentNotValidException.class)
public BaseErrorResponse validationException(MethodArgumentNotValidException e) {
String message = e.getBindingResult()
.getFieldErrors()
.stream()
.map(DefaultMessageSourceResolvable::getDefaultMessage)
.collect(Collectors.joining(", "));
return new BaseErrorResponse(message);
}

@ResponseStatus(HttpStatus.NOT_FOUND)
@ExceptionHandler({MemberNotFoundException.class, FontNotFoundException.class, BookmarkNotFoundException.class})
public BaseErrorResponse notFoundException(Exception e) {
Expand Down Expand Up @@ -169,4 +183,10 @@ public BaseErrorResponse fileNotFoundException(FileNotFoundException e) {
public BaseErrorResponse containsBadWordException(Exception e) {
return new BaseErrorResponse(e.getMessage());
}

@ResponseStatus(HttpStatus.UNAUTHORIZED)
@ExceptionHandler(AuthenticationRequiredException.class)
public BaseErrorResponse authenticationRequiredException(AuthenticationRequiredException e) {
return new BaseErrorResponse(e.getMessage());
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -95,7 +95,6 @@ public void initTokens() {
Member m = Member.builder()
.gender(Gender.MALE)
.provideId(provide.getId())
.terms(true)
.birth(LocalDate.now())
.nickname("Tester")
.profileImageKey(memberDefaults.getProfileImageKey())
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,12 +25,10 @@
import org.fontory.fontorybe.font.controller.dto.FontProgressResponse;
import org.fontory.fontorybe.font.controller.dto.FontProgressUpdateDTO;
import org.fontory.fontorybe.font.controller.dto.FontResponse;
import org.fontory.fontorybe.font.controller.dto.FontUpdateDTO;
import org.fontory.fontorybe.font.controller.dto.FontUpdateResponse;
import org.fontory.fontorybe.font.controller.port.FontService;
import org.fontory.fontorybe.font.domain.Font;
import org.springframework.data.domain.Page;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
Expand Down Expand Up @@ -120,27 +118,6 @@ public ResponseEntity<?> getFontProgress(@Login UserPrincipal userPrincipal) {
.body(fontsProgress);
}

@Operation(summary = "폰트 정보 수정")
@Parameter(name = "fontId", description = "수정할 폰트 ID")
@PutMapping("/{fontId}")
public ResponseEntity<?> updateFont(
@RequestBody FontUpdateDTO fontUpdateDTO,
@PathVariable Long fontId,
@Login UserPrincipal userPrincipal
) {
Long memberId = userPrincipal.getId();
log.info("Request received: Update font ID: {} by member ID: {}, request: {}",
fontId, memberId, toJson(fontUpdateDTO));

FontUpdateResponse fontUpdateResponse = fontService.update(memberId, fontId, fontUpdateDTO);
log.info("Response sent: Font ID: {} updated successfully, name: {}",
fontUpdateResponse.getId(), fontUpdateResponse.getName());

return ResponseEntity
.status(HttpStatus.OK)
.body(fontUpdateResponse);
}

@Operation(summary = "내가 제작한 폰트")
@GetMapping("/members")
public ResponseEntity<?> getFonts(
Expand Down Expand Up @@ -260,7 +237,7 @@ public ResponseEntity<?> getPopularFonts(@Login(required = false) UserPrincipal
@Parameter(name = "fontId", description = "수정할 폰트 ID")
@PatchMapping("/progress/{fontId}")
public ResponseEntity<?> updateFontProgress(
@RequestBody FontProgressUpdateDTO fontProgressUpdateDTO,
@RequestBody @Valid FontProgressUpdateDTO fontProgressUpdateDTO,
@PathVariable Long fontId
) {
log.info("Request received: Update font progress ID: {}, request: {}",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

import jakarta.validation.constraints.NotBlank;
import jakarta.validation.constraints.Pattern;
import jakarta.validation.constraints.Size;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Getter;
Expand All @@ -12,9 +13,17 @@
public class FontCreateDTO {

@NotBlank(message = "폰트 이름은 필수 입력 값입니다.")
@Size(min = 2, max = 30, message = "폰트 이름은 2자 이상 30자 이하로 입력해주세요.")
@Pattern(regexp = "^[가-힣0-9]{2,30}$", message = "한글과 숫자만 입력할 수 있습니다. (예: 가나다체123)")
private String name;

@NotBlank(message = "폰트 영어 이름은 필수 입력 값입니다.")
@Size(min = 2, max = 30, message = "폰트 이름은 2자 이상 30자 이하로 입력해주세요.")
@Pattern(regexp = "^[a-zA-Z0-9]{2,30}$", message = "영문 대소문자와 숫자만 입력할 수 있습니다. (예: ABCD123)")
private String engName;

@NotBlank(message = "폰트 예시는 필수 입력 값입니다.")
@Size(min = 10, max = 255, message = "폰트 예시는 10자 이상 255자 이하로 입력해주세요.")
private String example;

@Pattern(regexp = "^$|^01[016-9]\\d{7,8}$", message = "휴대폰 번호 형식이 올바르지 않습니다.")
Expand Down
Original file line number Diff line number Diff line change
@@ -1,13 +1,15 @@
package org.fontory.fontorybe.font.controller.dto;

import io.swagger.v3.oas.annotations.media.Schema;
import jakarta.validation.constraints.NotNull;
import lombok.Builder;
import lombok.Getter;
import org.fontory.fontorybe.font.infrastructure.entity.FontStatus;

@Getter
@Builder
public class FontProgressUpdateDTO {
@Schema(description = "폰트의 상태 (PROGRESS, DONE)")
@NotNull(message = "폰트 상태는 필수입니다.")
@Schema(description = "폰트의 상태 (PROGRESS, DONE, FAILED)")
private FontStatus status;
}

This file was deleted.

Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,6 @@
public interface FontService {
Font create(Long memberId, FontCreateDTO fontCreateDTO, FileUploadResult fileDetails);
List<FontProgressResponse> getFontProgress(Long memberId);
FontUpdateResponse update(Long memberId, Long fontId, FontUpdateDTO fontUpdateDTO);
Font getOrThrowById(Long id);
Page<FontResponse> getFonts(Long memberId, int page, int size);
FontResponse getFont(Long fondId, Long memberId);
Expand Down
45 changes: 8 additions & 37 deletions src/main/java/org/fontory/fontorybe/font/domain/Font.java
Original file line number Diff line number Diff line change
Expand Up @@ -6,10 +6,8 @@
import lombok.Builder;
import lombok.Getter;
import lombok.NoArgsConstructor;
import org.fontory.fontorybe.file.domain.FileUploadResult;
import org.fontory.fontorybe.font.controller.dto.FontCreateDTO;
import org.fontory.fontorybe.font.controller.dto.FontProgressUpdateDTO;
import org.fontory.fontorybe.font.controller.dto.FontUpdateDTO;
import org.fontory.fontorybe.font.infrastructure.entity.FontStatus;

@Getter
Expand All @@ -22,6 +20,8 @@ public class Font {

private String name;

private String engName;

private FontStatus status;

private String example;
Expand Down Expand Up @@ -53,6 +53,7 @@ public void increaseDownloadCount() {
public static Font from(FontCreateDTO fontCreateDTO, Long memberId, String key) {
return Font.builder()
.name(fontCreateDTO.getName())
.engName(fontCreateDTO.getEngName())
.status(FontStatus.PROGRESS)
.example(fontCreateDTO.getExample())
.key(key)
Expand All @@ -62,12 +63,13 @@ public static Font from(FontCreateDTO fontCreateDTO, Long memberId, String key)
.build();
}

public Font update(FontUpdateDTO fontUpdateDTO) {
public Font updateProgress(FontProgressUpdateDTO fontProgressUpdateDTO) {
return Font.builder()
.name(fontUpdateDTO.getName())
.example(fontUpdateDTO.getExample())
.name(this.name)
.engName(this.engName)
.example(this.example)
.id(this.id)
.status(this.status)
.status(fontProgressUpdateDTO.getStatus())
.downloadCount(this.downloadCount)
.bookmarkCount(this.bookmarkCount)
.key(this.key)
Expand All @@ -76,35 +78,4 @@ public Font update(FontUpdateDTO fontUpdateDTO) {
.updatedAt(this.updatedAt)
.build();
}

public Font updateProgress(FontProgressUpdateDTO fontProgressUpdateDTO, Long fontId) {

if (fontProgressUpdateDTO.getStatus() == FontStatus.DONE) {
return Font.builder()
.name(this.name)
.example(this.example)
.id(this.id)
.status(fontProgressUpdateDTO.getStatus())
.downloadCount(this.downloadCount)
.bookmarkCount(this.bookmarkCount)
.key(this.key)
.memberId(this.memberId)
.createdAt(this.createdAt)
.updatedAt(this.updatedAt)
.build();
} else {
return Font.builder()
.name(this.name)
.example(this.example)
.id(this.id)
.status(fontProgressUpdateDTO.getStatus())
.downloadCount(this.downloadCount)
.bookmarkCount(this.bookmarkCount)
.key(this.key)
.memberId(this.memberId)
.createdAt(this.createdAt)
.updatedAt(this.updatedAt)
.build();
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,8 @@ public class FontEntity extends BaseEntity {

private String name;

private String engName;

@Enumerated(EnumType.STRING)
private FontStatus status;

Expand All @@ -49,6 +51,7 @@ public Font toModel() {
return Font.builder()
.id(id)
.name(name)
.engName(engName)
.status(status)
.example(example)
.downloadCount(downloadCount)
Expand All @@ -64,6 +67,7 @@ public static FontEntity from(Font font) {
return FontEntity.builder()
.id(font.getId())
.name(font.getName())
.engName(font.getEngName())
.status(font.getStatus())
.example(font.getExample())
.downloadCount(font.getDownloadCount())
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,6 @@
import org.fontory.fontorybe.font.controller.dto.FontProgressResponse;
import org.fontory.fontorybe.font.controller.dto.FontProgressUpdateDTO;
import org.fontory.fontorybe.font.controller.dto.FontResponse;
import org.fontory.fontorybe.font.controller.dto.FontUpdateDTO;
import org.fontory.fontorybe.font.controller.dto.FontUpdateResponse;
import org.fontory.fontorybe.font.controller.port.FontService;
import org.fontory.fontorybe.font.domain.Font;
Expand Down Expand Up @@ -65,7 +64,7 @@ public Font create(Long memberId, FontCreateDTO fontCreateDTO, FileUploadResult
throw new FontDuplicateNameExistsException();
}

checkContainsBadWord(fontCreateDTO.getName(), fontCreateDTO.getExample());
checkFontNameAndExampleContainsBadWord(fontCreateDTO.getName(), fontCreateDTO.getEngName(), fontCreateDTO.getExample());

FileMetadata fileMetadata = fileService.getOrThrowById(fileDetails.getId());

Expand Down Expand Up @@ -97,23 +96,6 @@ public List<FontProgressResponse> getFontProgress(Long memberId) {
return result;
}

@Override
@Transactional
public FontUpdateResponse update(Long memberId, Long fontId, FontUpdateDTO fontUpdateDTO) {
log.info("Service executing: Updating font ID: {} for member ID: {}", fontId, memberId);
Member member = memberLookupService.getOrThrowById(memberId);
Font targetFont = getOrThrowById(fontId);

checkFontOwnership(member.getId(), targetFont.getMemberId());
checkContainsBadWord(fontUpdateDTO.getName(), fontUpdateDTO.getExample());

Font updatedFont = fontRepository.save(targetFont.update(fontUpdateDTO));
String woff2Url = cloudStorageService.getWoff2Url(updatedFont.getKey());

log.info("Service completed: Font ID: {} updated successfully", fontId);
return FontUpdateResponse.from(updatedFont, woff2Url);
}

@Override
@Transactional(readOnly = true)
public Font getOrThrowById(Long id) {
Expand Down Expand Up @@ -316,7 +298,7 @@ public FontUpdateResponse updateProgress(Long fontId, FontProgressUpdateDTO font
log.info("Service executing: Updating font ID: {}", fontId);
Font targetFont = getOrThrowById(fontId);

Font updatedFont = fontRepository.save(targetFont.updateProgress(fontProgressUpdateDTO, fontId));
Font updatedFont = fontRepository.save(targetFont.updateProgress(fontProgressUpdateDTO));
String woff2Url = cloudStorageService.getWoff2Url(updatedFont.getKey());

if (fontProgressUpdateDTO.getStatus() == FontStatus.DONE) {
Expand Down Expand Up @@ -375,11 +357,11 @@ private void checkFontStatusIsDone(Font targetFont) {
}
}

private void checkContainsBadWord(String name, String example) {
log.debug("Service detail: Checking bad word: name={}, example={}", name, example);
private void checkFontNameAndExampleContainsBadWord(String name, String engName, String example) {
log.debug("Service detail: Checking bad word: name={}, engName={} example={}", name, engName, example);

if (badWordFiltering.blankCheck(name) || badWordFiltering.blankCheck(example)) {
log.warn("Service warning: Font contains bad word: name={}, example={}", name, example);
if (badWordFiltering.blankCheck(name) || badWordFiltering.blankCheck(engName) || badWordFiltering.blankCheck(example)) {
log.warn("Service warning: Font contains bad word: name={}, engName={}, example={}", name, engName, example);
throw new FontContainsBadWordException();
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ public class FontRequestProduceDto {
private Long fontId;
private String fileKey;
private String fontName;
private String fontEngName;
private String templateURL;
private String author;
private String requestUUID;
Expand All @@ -25,6 +26,7 @@ public static FontRequestProduceDto from(Font font, Member member, String templa
.fileKey(font.getKey())
.fontId(font.getId())
.fontName(font.getName())
.fontEngName(font.getEngName())
.templateURL(templateUrl)
.author(member.getNickname())
.requestUUID(MDC.get("requestId"))
Expand Down
Loading
Loading