diff --git a/build.gradle b/build.gradle index 4d1c7b6..9af4de8 100644 --- a/build.gradle +++ b/build.gradle @@ -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' diff --git a/docker-compose.yml b/docker-compose.yml index 3fb6e4e..8a4253a 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -7,7 +7,7 @@ services: container_name: fontory-mariadb environment: MYSQL_ROOT_PASSWORD: rootPW - MYSQL_DATRABASE: FONTORY + MYSQL_DATABASE: FONTORY MYSQL_USER: fontory MYSQL_PASSWORD: fontoryPW ports: diff --git a/src/main/java/org/fontory/fontorybe/FonToryBeApplication.java b/src/main/java/org/fontory/fontorybe/FonToryBeApplication.java index 33b4b0b..01c1686 100644 --- a/src/main/java/org/fontory/fontorybe/FonToryBeApplication.java +++ b/src/main/java/org/fontory/fontorybe/FonToryBeApplication.java @@ -10,12 +10,14 @@ import org.springframework.context.annotation.Bean; import org.springframework.core.env.Environment; import org.springframework.data.jpa.repository.config.EnableJpaAuditing; +import org.springframework.retry.annotation.EnableRetry; import org.springframework.scheduling.annotation.EnableAsync; import lombok.extern.slf4j.Slf4j; @Slf4j @EnableAsync +@EnableRetry @EnableJpaAuditing @SpringBootApplication @EnableConfigurationProperties({JwtProperties.class, MemberDefaults.class}) diff --git a/src/main/java/org/fontory/fontorybe/authentication/adapter/inbound/CustomOauth2FailureHandler.java b/src/main/java/org/fontory/fontorybe/authentication/adapter/inbound/CustomOauth2FailureHandler.java index 2173d76..be035f3 100644 --- a/src/main/java/org/fontory/fontorybe/authentication/adapter/inbound/CustomOauth2FailureHandler.java +++ b/src/main/java/org/fontory/fontorybe/authentication/adapter/inbound/CustomOauth2FailureHandler.java @@ -5,6 +5,7 @@ import jakarta.servlet.http.HttpServletRequest; import jakarta.servlet.http.HttpServletResponse; import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; import org.springframework.security.core.AuthenticationException; import org.springframework.security.web.authentication.AuthenticationFailureHandler; import org.springframework.stereotype.Component; @@ -13,6 +14,7 @@ import java.util.HashMap; import java.util.Map; +@Slf4j @Component @RequiredArgsConstructor public class CustomOauth2FailureHandler implements AuthenticationFailureHandler { @@ -22,8 +24,18 @@ public class CustomOauth2FailureHandler implements AuthenticationFailureHandler public void onAuthenticationFailure(HttpServletRequest request, HttpServletResponse response, AuthenticationException exception) throws IOException, ServletException { + log.warn("OAuth2 authentication failed: errorMessage={}, exceptionType={}", + exception.getMessage(), exception.getClass().getSimpleName()); + + String requestUrl = request.getRequestURL().toString(); + String queryString = request.getQueryString(); + log.debug("Failed OAuth2 request details: url={}, queryString={}", requestUrl, queryString); + Map attributes = new HashMap<>(); attributes.put("message", "error occurred during authentication"); + + log.info("Sending OAuth2 authentication failure response: status={}", HttpServletResponse.SC_UNAUTHORIZED); + response.setContentType("application/json"); response.setStatus(HttpServletResponse.SC_UNAUTHORIZED); response.getWriter().write(objectMapper.writeValueAsString(attributes)); diff --git a/src/main/java/org/fontory/fontorybe/authentication/adapter/inbound/CustomOauth2SuccessHandler.java b/src/main/java/org/fontory/fontorybe/authentication/adapter/inbound/CustomOauth2SuccessHandler.java index 134b0ef..57a5f5f 100644 --- a/src/main/java/org/fontory/fontorybe/authentication/adapter/inbound/CustomOauth2SuccessHandler.java +++ b/src/main/java/org/fontory/fontorybe/authentication/adapter/inbound/CustomOauth2SuccessHandler.java @@ -3,6 +3,7 @@ import jakarta.servlet.http.HttpServletRequest; import jakarta.servlet.http.HttpServletResponse; import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; import org.fontory.fontorybe.authentication.application.dto.ResponseCookies; import org.fontory.fontorybe.authentication.application.AuthService; import org.fontory.fontorybe.authentication.application.port.CookieUtils; @@ -21,6 +22,7 @@ import java.io.IOException; import java.util.Objects; +@Slf4j @Component @RequiredArgsConstructor public class CustomOauth2SuccessHandler implements AuthenticationSuccessHandler { @@ -37,19 +39,39 @@ public class CustomOauth2SuccessHandler implements AuthenticationSuccessHandler public void onAuthenticationSuccess(HttpServletRequest request, HttpServletResponse response, Authentication authentication) throws IOException { + log.info("OAuth2 authentication success handler triggered"); + OAuth2User authUser = (OAuth2User) authentication.getPrincipal(); Provide provide = authUser.getAttribute("provide"); Objects.requireNonNull(provide, "OAuth2User must have 'provide' attribute"); + + log.info("Processing successful OAuth2 login: provideId={}, provider={}, email={}", + provide.getId(), provide.getProvider(), provide.getEmail()); Member member = memberOnboardService.fetchOrCreateMember(provide); + log.info("Member fetched/created: memberId={}, status={}", + member.getId(), member.getStatus()); + ResponseCookies cookies = authService.issueAuthCookies(member); + log.debug("Auth cookies issued for member: memberId={}", member.getId()); + cookieUtils.addCookies(response, cookies); + log.debug("Auth cookies added to response: memberId={}", member.getId()); - redirectStrategy.sendRedirect(request, response, buildRedirectUrl(member)); + String redirectUrl = buildRedirectUrl(member); + log.info("Redirecting user after successful OAuth2 login: memberId={}, status={}, redirectUrl={}", + member.getId(), member.getStatus(), redirectUrl); + + redirectStrategy.sendRedirect(request, response, redirectUrl); } private String buildRedirectUrl(Member member) { String path = (member.getStatus() == MemberStatus.ONBOARDING) ? signUpPath : authPath; - return baseUrl + path; + String redirectUrl = baseUrl + path; + + log.debug("Building redirect URL: memberStatus={}, path={}, fullUrl={}", + member.getStatus(), path, redirectUrl); + + return redirectUrl; } } diff --git a/src/main/java/org/fontory/fontorybe/authentication/adapter/inbound/CustomOauth2UserService.java b/src/main/java/org/fontory/fontorybe/authentication/adapter/inbound/CustomOauth2UserService.java index 9c847a8..3e756ed 100644 --- a/src/main/java/org/fontory/fontorybe/authentication/adapter/inbound/CustomOauth2UserService.java +++ b/src/main/java/org/fontory/fontorybe/authentication/adapter/inbound/CustomOauth2UserService.java @@ -1,6 +1,7 @@ package org.fontory.fontorybe.authentication.adapter.inbound; import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; import org.fontory.fontorybe.authentication.domain.Auth2UserInfo; import org.fontory.fontorybe.provide.domain.Provide; import org.fontory.fontorybe.provide.infrastructure.entity.Provider; @@ -22,6 +23,7 @@ import static org.fontory.fontorybe.authentication.domain.Auth2UserInfo.getOAuth2UserInfo; +@Slf4j @Service @RequiredArgsConstructor public class CustomOauth2UserService implements OAuth2UserService { @@ -30,16 +32,26 @@ public class CustomOauth2UserService implements OAuth2UserService delegate = new DefaultOAuth2UserService(); OAuth2User oAuth2User = delegate.loadUser(userRequest); + log.debug("OAuth2 user loaded from provider: provider={}", registrationId); String userNameAttributeName = userRequest.getClientRegistration().getProviderDetails().getUserInfoEndpoint().getUserNameAttributeName(); Provider provider = Provider.from(userRequest.getClientRegistration().getRegistrationId()); Map attributes = new HashMap<>(oAuth2User.getAttributes()); Auth2UserInfo oAuth2UserInfo = getOAuth2UserInfo(provider, attributes, userNameAttributeName); + + log.info("OAuth2 user info extracted: provider={}, userIdentifier={}, email={}", + provider, oAuth2UserInfo.getUserIdentifier(), oAuth2UserInfo.getEmail()); Provide provide = getProvide(oAuth2UserInfo); attributes.put("provide", provide); + + log.info("OAuth2 authentication successful: provider={}, provideId={}", + provider, provide.getId()); return new DefaultOAuth2User( Collections.singleton(new SimpleGrantedAuthority("ROLE_USER")), @@ -51,17 +63,28 @@ public OAuth2User loadUser(OAuth2UserRequest userRequest) throws OAuth2Authentic private Provide getProvide(Auth2UserInfo oAuth2UserInfo) { String userIdentifier = oAuth2UserInfo.getUserIdentifier(); Provider provider = oAuth2UserInfo.getProvider(); + + log.debug("Looking up provide info: userIdentifier={}, provider={}", userIdentifier, provider); Optional oAuthInfo = provideRepository.findByOAuthInfo(userIdentifier, provider); if (oAuthInfo.isEmpty() || oAuthInfo.get().getId() == null) { + log.info("Creating new provide entry: userIdentifier={}, provider={}, email={}", + userIdentifier, provider, oAuth2UserInfo.getEmail()); + Provide provide = Provide.builder() .providedId(userIdentifier) .email(oAuth2UserInfo.getEmail()) .provider(provider) .build(); - return provideRepository.save(provide); + Provide savedProvide = provideRepository.save(provide); + + log.info("New provide created: provideId={}, userIdentifier={}, provider={}", + savedProvide.getId(), userIdentifier, provider); + return savedProvide; } else { + log.info("Existing provide found: provideId={}, userIdentifier={}, provider={}", + oAuthInfo.get().getId(), userIdentifier, provider); return oAuthInfo.get(); } } diff --git a/src/main/java/org/fontory/fontorybe/authentication/adapter/outbound/JwtTokenProviderImpl.java b/src/main/java/org/fontory/fontorybe/authentication/adapter/outbound/JwtTokenProviderImpl.java index e635770..53db259 100644 --- a/src/main/java/org/fontory/fontorybe/authentication/adapter/outbound/JwtTokenProviderImpl.java +++ b/src/main/java/org/fontory/fontorybe/authentication/adapter/outbound/JwtTokenProviderImpl.java @@ -11,10 +11,12 @@ import org.springframework.security.authentication.UsernamePasswordAuthenticationToken; import org.springframework.security.core.Authentication; import org.springframework.stereotype.Component; +import lombok.extern.slf4j.Slf4j; import javax.crypto.SecretKey; import java.util.Date; +@Slf4j @Component public class JwtTokenProviderImpl implements JwtTokenProvider { @@ -36,6 +38,8 @@ private SecretKey getSigningKey(String key) { public JwtTokenProviderImpl( JwtProperties props) { + log.info("Initializing JWT token provider"); + this.accessSecretKey = getSigningKey(props.getAccessSecretKey()); this.refreshSecretKey = getSigningKey(props.getRefreshSecretKey()); this.provideSecretKey = getSigningKey(props.getProvideSecretKey()); @@ -46,75 +50,119 @@ public JwtTokenProviderImpl( this.provideJwtParser = Jwts.parserBuilder().setSigningKey(provideSecretKey).build(); this.fontCreateJwtParser = Jwts.parserBuilder().setSigningKey(fontCreateSecretKey).build(); this.props = props; + + log.debug("JWT token provider initialized with token validities - access: {}ms, refresh: {}ms", + props.getAccessTokenValidityMs(), props.getRefreshTokenValidityMs()); } public String generateTemporalProvideToken(String id) { + log.debug("Generating temporal provide token for id: {}", id); + Date now = new Date(); Date expiryDate = new Date(now.getTime() + props.getTempTokenValidityMs()); - return Jwts.builder() + String token = Jwts.builder() .setSubject(String.valueOf(id)) .setIssuedAt(now) .setExpiration(expiryDate) .signWith(this.provideSecretKey) .compact(); + + log.info("Temporal provide token generated: id={}, expiresAt={}", id, expiryDate); + return token; } public Long getProvideId(String token) { + log.debug("Extracting provide ID from token"); + Claims claims = provideJwtParser .parseClaimsJws(token) .getBody(); - return Long.valueOf(claims.getSubject()); + Long provideId = Long.valueOf(claims.getSubject()); + + log.debug("Provide ID extracted: {}", provideId); + return provideId; } public String generateAccessToken(UserPrincipal user) { + log.debug("Generating access token for user: {}", user.getId()); + Date now = new Date(); Date expiryDate = new Date(now.getTime() + props.getAccessTokenValidityMs()); - return Jwts.builder() + String token = Jwts.builder() .setSubject(String.valueOf(user.getId())) .setIssuedAt(now) .setExpiration(expiryDate) .signWith(this.accessSecretKey) .compact(); + + log.info("Access token generated: userId={}, expiresAt={}", user.getId(), expiryDate); + return token; } public String generateRefreshToken(UserPrincipal user) { + log.debug("Generating refresh token for user: {}", user.getId()); + Date now = new Date(); Date expiryDate = new Date(now.getTime() + props.getRefreshTokenValidityMs()); - return Jwts.builder() + String token = Jwts.builder() .setSubject(String.valueOf(user.getId())) .setIssuedAt(now) .setExpiration(expiryDate) .signWith(refreshSecretKey) .compact(); + + log.info("Refresh token generated: userId={}, expiresAt={}", user.getId(), expiryDate); + return token; } public Long getMemberIdFromAccessToken(String token) { + log.debug("Extracting member ID from access token"); + Claims claims = accessJwtParser .parseClaimsJws(token) .getBody(); - return Long.valueOf(claims.getSubject()); + Long memberId = Long.valueOf(claims.getSubject()); + + log.debug("Member ID extracted from access token: {}", memberId); + return memberId; } public Long getMemberIdFromRefreshToken(String token) { + log.debug("Extracting member ID from refresh token"); + Claims claims = refreshJwtParser .parseClaimsJws(token) .getBody(); - return Long.valueOf(claims.getSubject()); + Long memberId = Long.valueOf(claims.getSubject()); + + log.debug("Member ID extracted from refresh token: {}", memberId); + return memberId; } public Authentication getAuthenticationFromAccessToken(String token) { + log.debug("Creating authentication from access token"); + Claims claims = accessJwtParser .parseClaimsJws(token) .getBody(); Long id = Long.valueOf(claims.getSubject()); UserPrincipal principal = new UserPrincipal(id); - return new UsernamePasswordAuthenticationToken(principal, token, principal.getAuthorities()); + Authentication auth = new UsernamePasswordAuthenticationToken(principal, token, principal.getAuthorities()); + + log.info("Authentication created from access token: userId={}, authorities={}", + id, principal.getAuthorities()); + return auth; } public String getFontCreateServer(String token) { + log.debug("Validating font create server token"); + Claims claims = fontCreateJwtParser .parseClaimsJws(token) .getBody(); - return claims.getSubject(); + String subject = claims.getSubject(); + + log.debug("Font create server token validated: subject={}", subject); + return subject; } } diff --git a/src/main/java/org/fontory/fontorybe/authentication/application/AuthService.java b/src/main/java/org/fontory/fontorybe/authentication/application/AuthService.java index 03d456b..a6f6c12 100644 --- a/src/main/java/org/fontory/fontorybe/authentication/application/AuthService.java +++ b/src/main/java/org/fontory/fontorybe/authentication/application/AuthService.java @@ -3,6 +3,7 @@ import jakarta.servlet.http.HttpServletResponse; import lombok.Builder; import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; import org.fontory.fontorybe.authentication.application.dto.ResponseCookies; import org.fontory.fontorybe.authentication.application.port.CookieUtils; import org.fontory.fontorybe.authentication.application.port.JwtTokenProvider; @@ -14,6 +15,7 @@ import org.fontory.fontorybe.member.domain.Member; import org.springframework.stereotype.Service; +@Slf4j @Builder @Service @RequiredArgsConstructor @@ -29,12 +31,16 @@ public class AuthService { * 기존에 토큰이 존재한다면 제거, 기존 토큰이 존재할 필요 X */ private TokenResponse issueNewTokens(Member member) { + log.info("Issuing new token pair for member: memberId={}, provideId={}", + member.getId(), member.getProvideId()); + UserPrincipal user = UserPrincipal.from(member); String accessToken = jwtTokenProvider.generateAccessToken(user); String refreshToken = jwtTokenProvider.generateRefreshToken(user); tokenStorage.saveRefreshToken(member, refreshToken); + log.debug("Refresh token stored in Redis for member: memberId={}", member.getId()); return TokenResponse.from(accessToken, refreshToken); } @@ -43,30 +49,49 @@ private TokenResponse issueNewTokens(Member member) { * 쿠키 발급 */ public ResponseCookies issueAuthCookies(Member member) { + log.info("Creating auth cookies for member: memberId={}, status={}", + member.getId(), member.getStatus()); + TokenResponse tokenResponse = issueNewTokens(member); - return ResponseCookies.from( + ResponseCookies cookies = ResponseCookies.from( cookieUtils.createAccessTokenCookie(tokenResponse.getAccessToken()), cookieUtils.createRefreshTokenCookie(tokenResponse.getRefreshToken()) ); + + log.debug("Auth cookies created successfully for member: memberId={}", member.getId()); + return cookies; } /** * 쿠키 재발급 */ public ResponseCookies refreshAuthCookies(Long memberId, String providedRefreshToken) { + log.info("Refreshing auth cookies for member: memberId={}", memberId); + Member member = memberLookupService.getOrThrowById(memberId); String storedRefreshToken = tokenStorage.getRefreshToken(member); - if (storedRefreshToken == null || !storedRefreshToken.equals(providedRefreshToken)) { + if (storedRefreshToken == null) { + log.warn("No stored refresh token found for member: memberId={}", memberId); throw new InvalidRefreshTokenException(); } - + + if (!storedRefreshToken.equals(providedRefreshToken)) { + log.warn("Refresh token mismatch for member: memberId={}", memberId); + throw new InvalidRefreshTokenException(); + } + + log.info("Refresh token validated successfully, issuing new tokens: memberId={}", memberId); return issueAuthCookies(member); } public void clearAuthCookies(HttpServletResponse res, Long memberId) { + log.info("Clearing auth cookies for member: memberId={}", memberId); + Member member = memberLookupService.getOrThrowById(memberId); cookieUtils.clearAuthCookies(res); tokenStorage.removeRefreshToken(member); + + log.info("Auth cookies and refresh token cleared successfully: memberId={}", memberId); } } diff --git a/src/main/java/org/fontory/fontorybe/authentication/domain/exception/AuthenticationRequiredException.java b/src/main/java/org/fontory/fontorybe/authentication/domain/exception/AuthenticationRequiredException.java new file mode 100644 index 0000000..26a9f8f --- /dev/null +++ b/src/main/java/org/fontory/fontorybe/authentication/domain/exception/AuthenticationRequiredException.java @@ -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"); + } +} diff --git a/src/main/java/org/fontory/fontorybe/common/adapter/inbound/GlobalExceptionHandler.java b/src/main/java/org/fontory/fontorybe/common/adapter/inbound/GlobalExceptionHandler.java index f014499..0deb977 100644 --- a/src/main/java/org/fontory/fontorybe/common/adapter/inbound/GlobalExceptionHandler.java +++ b/src/main/java/org/fontory/fontorybe/common/adapter/inbound/GlobalExceptionHandler.java @@ -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; @@ -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; @@ -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) { @@ -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()); + } } diff --git a/src/main/java/org/fontory/fontorybe/common/adapter/outbound/DiscordExceptionLoggingAspect.java b/src/main/java/org/fontory/fontorybe/common/adapter/outbound/DiscordExceptionLoggingAspect.java index 5280b43..ed397da 100644 --- a/src/main/java/org/fontory/fontorybe/common/adapter/outbound/DiscordExceptionLoggingAspect.java +++ b/src/main/java/org/fontory/fontorybe/common/adapter/outbound/DiscordExceptionLoggingAspect.java @@ -156,24 +156,28 @@ private String buildStackTrace(Throwable ex) { */ @Async protected void sendToDiscord(String payloadJson, String fullStackTrace) { - byte[] stackTraceBytes = fullStackTrace.getBytes(StandardCharsets.UTF_8); - ByteArrayResource stackTraceResource = new ByteArrayResource(stackTraceBytes) { - @Override - public String getFilename() { - return "stacktrace.txt"; - } - }; + try { + byte[] stackTraceBytes = fullStackTrace.getBytes(StandardCharsets.UTF_8); + ByteArrayResource stackTraceResource = new ByteArrayResource(stackTraceBytes) { + @Override + public String getFilename() { + return "stacktrace.txt"; + } + }; - LinkedMultiValueMap multipartBody = new LinkedMultiValueMap<>(); - multipartBody.add("payload_json", payloadJson); - multipartBody.add("file", stackTraceResource); + LinkedMultiValueMap multipartBody = new LinkedMultiValueMap<>(); + multipartBody.add("payload_json", payloadJson); + multipartBody.add("file", stackTraceResource); - HttpHeaders headers = new HttpHeaders(); - headers.setContentType(MediaType.MULTIPART_FORM_DATA); + HttpHeaders headers = new HttpHeaders(); + headers.setContentType(MediaType.MULTIPART_FORM_DATA); - HttpEntity> requestEntity = - new HttpEntity<>(multipartBody, headers); + HttpEntity> requestEntity = + new HttpEntity<>(multipartBody, headers); - restTemplate.postForEntity(discordWebhookUrl, requestEntity, String.class); + restTemplate.postForEntity(discordWebhookUrl, requestEntity, String.class); + } catch (Exception e) { + log.warn("Exception occured while sending stacktrace to Discord: {}", e); + } } } \ No newline at end of file diff --git a/src/main/java/org/fontory/fontorybe/common/application/DevTokenInitializer.java b/src/main/java/org/fontory/fontorybe/common/application/DevTokenInitializer.java index 132b4f6..7de323e 100644 --- a/src/main/java/org/fontory/fontorybe/common/application/DevTokenInitializer.java +++ b/src/main/java/org/fontory/fontorybe/common/application/DevTokenInitializer.java @@ -14,6 +14,7 @@ import org.fontory.fontorybe.member.domain.Member; import org.fontory.fontorybe.member.domain.MemberDefaults; import org.fontory.fontorybe.member.infrastructure.entity.Gender; +import org.fontory.fontorybe.member.infrastructure.entity.MemberStatus; import org.fontory.fontorybe.member.service.port.MemberRepository; import org.fontory.fontorybe.provide.domain.Provide; import org.fontory.fontorybe.provide.infrastructure.entity.Provider; @@ -95,10 +96,9 @@ public void initTokens() { Member m = Member.builder() .gender(Gender.MALE) .provideId(provide.getId()) - .terms(true) .birth(LocalDate.now()) .nickname("Tester") - .profileImageKey(memberDefaults.getProfileImageKey()) + .status(MemberStatus.ONBOARDING) .build(); return memberRepository.save(m); }); diff --git a/src/main/java/org/fontory/fontorybe/config/WebConfig.java b/src/main/java/org/fontory/fontorybe/config/WebConfig.java index ea37b98..0b4cb6e 100644 --- a/src/main/java/org/fontory/fontorybe/config/WebConfig.java +++ b/src/main/java/org/fontory/fontorybe/config/WebConfig.java @@ -40,6 +40,7 @@ public void addInterceptors(InterceptorRegistry registry) { public CorsConfigurationSource corsConfigurationSource() { CorsConfiguration configuration = new CorsConfiguration(); configuration.setAllowedOrigins(List.of( + "http://localhost:3000", "http://localhost:5173", "https://www.fontory.co.kr", "https://fontory.co.kr", diff --git a/src/main/java/org/fontory/fontorybe/file/adapter/outbound/s3/AmazonS3BucketService.java b/src/main/java/org/fontory/fontorybe/file/adapter/outbound/s3/AmazonS3BucketService.java index a18b806..21e446e 100644 --- a/src/main/java/org/fontory/fontorybe/file/adapter/outbound/s3/AmazonS3BucketService.java +++ b/src/main/java/org/fontory/fontorybe/file/adapter/outbound/s3/AmazonS3BucketService.java @@ -27,40 +27,15 @@ public class AmazonS3BucketService implements CloudStorageService { private final S3Client s3; private final S3Config s3Config; private final ClockHolder clockHolder; - private String profileImageBucketName; private String fontPaperBucketName; - private String profileImagePrefix; private String fontPaperPrefix; @PostConstruct void init() { - profileImageBucketName = s3Config.getBucketName(FileType.PROFILE_IMAGE); fontPaperBucketName = s3Config.getBucketName(FileType.FONT_PAPER); - profileImagePrefix = s3Config.getPrefix(FileType.PROFILE_IMAGE); fontPaperPrefix = s3Config.getPrefix(FileType.FONT_PAPER); } - @Override - public FileMetadata uploadProfileImage(FileCreate request, String key) { - log.info("Uploading profile image: fileName={}, contentType={}, size={} bytes, fileKey={}", - request.getFileName(), request.getFile().getContentType(), request.getFile().getSize(), key); - - AmazonS3PutRequest amazonS3PutRequest = AmazonS3PutRequest.from( - request, - key, - profileImageBucketName, - profileImagePrefix, - clockHolder.getCurrentTimeStamp()); - - log.info("Profile image uploaded successfully: fileKey={}, bucket={}", key, profileImageBucketName); - return uploadFile(amazonS3PutRequest).toModel(); - } - - @Override - public String getProfileImageUrl(String key) { - return getFileUrl(FileType.PROFILE_IMAGE, key); - } - @Override public String getFontPaperUrl(String key) { return getFileUrl(FileType.FONT_PAPER, key); diff --git a/src/main/java/org/fontory/fontorybe/file/adapter/outbound/s3/ProfileImageUpdateListener.java b/src/main/java/org/fontory/fontorybe/file/adapter/outbound/s3/ProfileImageUpdateListener.java deleted file mode 100644 index ecfc80f..0000000 --- a/src/main/java/org/fontory/fontorybe/file/adapter/outbound/s3/ProfileImageUpdateListener.java +++ /dev/null @@ -1,57 +0,0 @@ -package org.fontory.fontorybe.file.adapter.outbound.s3; - -import jakarta.annotation.PostConstruct; -import lombok.RequiredArgsConstructor; -import lombok.extern.slf4j.Slf4j; -import org.fontory.fontorybe.config.S3Config; -import org.fontory.fontorybe.file.adapter.outbound.s3.dto.ProfileImageUpdatedEvent; -import org.fontory.fontorybe.file.domain.FileType; -import org.springframework.stereotype.Component; -import org.springframework.transaction.event.TransactionPhase; -import org.springframework.transaction.event.TransactionalEventListener; -import software.amazon.awssdk.services.s3.S3Client; -import software.amazon.awssdk.services.s3.model.CopyObjectRequest; -import software.amazon.awssdk.services.s3.model.DeleteObjectRequest; - -@Slf4j -@Component -@RequiredArgsConstructor -public class ProfileImageUpdateListener { - private final S3Client s3; - private final S3Config s3Config; - private String profileImageBucketName; - private String profileImagePrefix; - - @PostConstruct - void init() { - profileImageBucketName = s3Config.getBucketName(FileType.PROFILE_IMAGE); - profileImagePrefix = s3Config.getPrefix(FileType.PROFILE_IMAGE); - } - - @TransactionalEventListener(phase = TransactionPhase.BEFORE_COMMIT) - public void beforeCommit(ProfileImageUpdatedEvent event) { - s3.copyObject(CopyObjectRequest.builder() - .sourceBucket(profileImageBucketName) - .sourceKey(profileImagePrefix + "/" + event.getTempKey()) - .destinationBucket(profileImageBucketName) - .destinationKey(profileImagePrefix + "/" + event.getFixedKey()) - .build()); - - s3.deleteObject(DeleteObjectRequest.builder() - .bucket(profileImageBucketName) - .key(profileImagePrefix + "/" + event.getTempKey()) - .build()); - } - - @TransactionalEventListener(phase = TransactionPhase.AFTER_ROLLBACK) - public void afterRollback(ProfileImageUpdatedEvent event) { - try { - s3.deleteObject(DeleteObjectRequest.builder() - .bucket(profileImageBucketName) - .key(profileImagePrefix + "/" + event.getTempKey()) - .build()); - } catch (Exception e) { - log.warn("Rollback profile image failed", e); - } - } -} diff --git a/src/main/java/org/fontory/fontorybe/file/adapter/outbound/s3/dto/ProfileImageUpdatedEvent.java b/src/main/java/org/fontory/fontorybe/file/adapter/outbound/s3/dto/ProfileImageUpdatedEvent.java deleted file mode 100644 index 9515bba..0000000 --- a/src/main/java/org/fontory/fontorybe/file/adapter/outbound/s3/dto/ProfileImageUpdatedEvent.java +++ /dev/null @@ -1,11 +0,0 @@ -package org.fontory.fontorybe.file.adapter.outbound.s3.dto; - -import lombok.Getter; -import lombok.RequiredArgsConstructor; - -@Getter -@RequiredArgsConstructor -public class ProfileImageUpdatedEvent { - private final String tempKey; - private final String fixedKey; -} diff --git a/src/main/java/org/fontory/fontorybe/file/application/FileServiceImpl.java b/src/main/java/org/fontory/fontorybe/file/application/FileServiceImpl.java index 7c66391..36e0a59 100644 --- a/src/main/java/org/fontory/fontorybe/file/application/FileServiceImpl.java +++ b/src/main/java/org/fontory/fontorybe/file/application/FileServiceImpl.java @@ -4,7 +4,6 @@ import java.util.UUID; import org.fontory.fontorybe.file.adapter.inbound.FileRequestMapper; -import org.fontory.fontorybe.file.adapter.outbound.s3.dto.ProfileImageUpdatedEvent; import org.fontory.fontorybe.file.application.port.CloudStorageService; import org.fontory.fontorybe.file.application.port.FileRepository; import org.fontory.fontorybe.file.application.port.FileService; @@ -13,7 +12,6 @@ import org.fontory.fontorybe.file.domain.FileUploadResult; import org.fontory.fontorybe.file.domain.exception.FileNotFoundException; import org.fontory.fontorybe.member.controller.port.MemberLookupService; -import org.fontory.fontorybe.member.controller.port.MemberUpdateService; import org.fontory.fontorybe.member.domain.Member; import org.fontory.fontorybe.member.domain.MemberDefaults; import org.springframework.context.ApplicationEventPublisher; @@ -35,7 +33,6 @@ public class FileServiceImpl implements FileService { private final FileRequestMapper fileRequestMapper; private final CloudStorageService cloudStorageService; private final MemberLookupService memberLookupService; - private final MemberUpdateService memberUpdateService; private final ApplicationEventPublisher eventPublisher; @Override @@ -46,35 +43,6 @@ public FileMetadata getOrThrowById(Long id) { .orElseThrow(() -> new FileNotFoundException(id)); } - @Override - @Transactional - public FileUploadResult uploadProfileImage(MultipartFile file, Long memberId) { - log.info("Processing profile image upload: fileName={}, memberId={}", file.getOriginalFilename(), memberId); - - Member requestMember = memberLookupService.getOrThrowById(memberId); - FileCreate profileImageFileCreate = fileRequestMapper.toProfileImageFileCreate(file, requestMember); - boolean isInitial = memberDefaults.getProfileImageKey().equals(requestMember.getProfileImageKey()); - String fixedKey = isInitial - ? UUID.randomUUID().toString() - : requestMember.getProfileImageKey(); - - String tempKey = UUID.randomUUID().toString(); - - log.info("Uploading profile image to cloud storage: memberId={}, tempKey={}", memberId, tempKey); - FileMetadata metadata = cloudStorageService.uploadProfileImage(profileImageFileCreate, tempKey); - metadata.updateKey(fixedKey); - FileMetadata savedMetaData = fileRepository.save(metadata); - Member updated = memberUpdateService.setProfileImageKey(requestMember, fixedKey); - - log.info("Updating member profile image key: memberId={}, memberProfileImageKey={}", updated.getId(), updated.getProfileImageKey()); - log.info("Publishing image update event: tempKey={}, fixedKey={}", tempKey, fixedKey); - eventPublisher.publishEvent(new ProfileImageUpdatedEvent(tempKey, fixedKey)); - String fileUrl = cloudStorageService.getProfileImageUrl(fixedKey); - FileUploadResult result = FileUploadResult.from(savedMetaData, fileUrl); - log.info("Profile image upload completed successfully: memberId={}, fileUrl={}", memberId, fileUrl); - return result; - } - @Override @Transactional public FileUploadResult uploadFontTemplateImage(MultipartFile file, Long memberId) { diff --git a/src/main/java/org/fontory/fontorybe/file/application/port/CloudStorageService.java b/src/main/java/org/fontory/fontorybe/file/application/port/CloudStorageService.java index e143ec6..19b98d2 100644 --- a/src/main/java/org/fontory/fontorybe/file/application/port/CloudStorageService.java +++ b/src/main/java/org/fontory/fontorybe/file/application/port/CloudStorageService.java @@ -4,9 +4,7 @@ import org.fontory.fontorybe.file.domain.FileMetadata; public interface CloudStorageService { - FileMetadata uploadProfileImage(FileCreate fileCreate, String key); FileMetadata uploadFontTemplateImage(FileCreate request); - String getProfileImageUrl(String key); String getFontPaperUrl(String key); String getWoff2Url(String key); String getTtfUrl(String key); diff --git a/src/main/java/org/fontory/fontorybe/file/application/port/FileService.java b/src/main/java/org/fontory/fontorybe/file/application/port/FileService.java index 604b00c..47ca951 100644 --- a/src/main/java/org/fontory/fontorybe/file/application/port/FileService.java +++ b/src/main/java/org/fontory/fontorybe/file/application/port/FileService.java @@ -5,8 +5,6 @@ import org.springframework.web.multipart.MultipartFile; public interface FileService { - - FileUploadResult uploadProfileImage(MultipartFile file, Long memberId); FileMetadata getOrThrowById(Long id); FileUploadResult uploadFontTemplateImage(MultipartFile file, Long memberId); } diff --git a/src/main/java/org/fontory/fontorybe/file/infrastructure/ProfileImageDlqRepository.java b/src/main/java/org/fontory/fontorybe/file/infrastructure/ProfileImageDlqRepository.java new file mode 100644 index 0000000..5ae966b --- /dev/null +++ b/src/main/java/org/fontory/fontorybe/file/infrastructure/ProfileImageDlqRepository.java @@ -0,0 +1,7 @@ +package org.fontory.fontorybe.file.infrastructure; + +import org.fontory.fontorybe.file.infrastructure.entity.ProfileImageDlq; +import org.springframework.data.jpa.repository.JpaRepository; + +public interface ProfileImageDlqRepository extends JpaRepository { +} diff --git a/src/main/java/org/fontory/fontorybe/file/infrastructure/entity/ProfileImageDlq.java b/src/main/java/org/fontory/fontorybe/file/infrastructure/entity/ProfileImageDlq.java new file mode 100644 index 0000000..33ff794 --- /dev/null +++ b/src/main/java/org/fontory/fontorybe/file/infrastructure/entity/ProfileImageDlq.java @@ -0,0 +1,22 @@ +package org.fontory.fontorybe.file.infrastructure.entity; + +import jakarta.persistence.*; +import lombok.*; + +import java.time.LocalDateTime; + +@Entity +@Getter +@Table(name = "dlq") +@NoArgsConstructor(access = AccessLevel.PROTECTED) +@AllArgsConstructor(access = AccessLevel.PRIVATE) +@Builder +public class ProfileImageDlq{ + @Id + @GeneratedValue(strategy = GenerationType.IDENTITY) + private Long id; + private Long memberId; + private String tempKey; + private String fixKey; + private LocalDateTime time; +} diff --git a/src/main/java/org/fontory/fontorybe/font/CoolSmsEventListener.java b/src/main/java/org/fontory/fontorybe/font/CoolSmsEventListener.java new file mode 100644 index 0000000..ff276af --- /dev/null +++ b/src/main/java/org/fontory/fontorybe/font/CoolSmsEventListener.java @@ -0,0 +1,48 @@ +package org.fontory.fontorybe.font; + +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.fontory.fontorybe.font.domain.Font; +import org.fontory.fontorybe.sms.application.port.PhoneNumberStorage; +import org.fontory.fontorybe.sms.application.port.SmsService; +import org.springframework.scheduling.annotation.Async; +import org.springframework.stereotype.Component; +import org.springframework.transaction.event.TransactionPhase; +import org.springframework.transaction.event.TransactionalEventListener; + +@Slf4j +@Component +@RequiredArgsConstructor +public class CoolSmsEventListener { + + private final PhoneNumberStorage phoneNumberStorage; + private final SmsService smsService; + + @Async + @TransactionalEventListener(phase = TransactionPhase.AFTER_COMMIT) + public void sendFontCreateRequestNotificationAndSavePhoneNumber(FontCreateRequestNotificationEvent e) { + Font font = e.getFont(); + String phoneNumber = e.getPhoneNumber(); + + log.info("sms send start & save phone number in redis - fontId={}, phoneNumber={}", font.getId(), phoneNumber); + + phoneNumberStorage.savePhoneNumber(font, phoneNumber); + smsService.sendFontCreateRequestNotification(phoneNumber, font.getName()); + + log.info("sms sent & phone number saved in redis - fontId={}, phoneNumber={}", font.getId(), phoneNumber); + } + + @Async + @TransactionalEventListener(phase = TransactionPhase.AFTER_COMMIT) + public void sendFontCreateCompleteNotificationAndRemovePhoneNumber(FontCreateCompleteNotificationEvent e) { + Font font = e.getFont(); + String phoneNumber = phoneNumberStorage.getPhoneNumber(font); + + log.info("sms send start & save phone number in redis - fontId={}, phoneNumber={}", font.getId(), phoneNumber); + + smsService.sendFontCreateCompleteNotification(phoneNumber, font.getName()); + phoneNumberStorage.removePhoneNumber(font); + + log.info("sms sent & phone number saved in redis - fontId={}, phoneNumber={}", font.getId(), phoneNumber); + } +} diff --git a/src/main/java/org/fontory/fontorybe/font/FontCreateCompleteNotificationEvent.java b/src/main/java/org/fontory/fontorybe/font/FontCreateCompleteNotificationEvent.java new file mode 100644 index 0000000..4c927c4 --- /dev/null +++ b/src/main/java/org/fontory/fontorybe/font/FontCreateCompleteNotificationEvent.java @@ -0,0 +1,11 @@ +package org.fontory.fontorybe.font; + +import lombok.Getter; +import lombok.RequiredArgsConstructor; +import org.fontory.fontorybe.font.domain.Font; + +@Getter +@RequiredArgsConstructor +public class FontCreateCompleteNotificationEvent { + private final Font font; +} diff --git a/src/main/java/org/fontory/fontorybe/font/FontCreateRequestNotificationEvent.java b/src/main/java/org/fontory/fontorybe/font/FontCreateRequestNotificationEvent.java new file mode 100644 index 0000000..1995bcb --- /dev/null +++ b/src/main/java/org/fontory/fontorybe/font/FontCreateRequestNotificationEvent.java @@ -0,0 +1,12 @@ +package org.fontory.fontorybe.font; + +import lombok.Getter; +import lombok.RequiredArgsConstructor; +import org.fontory.fontorybe.font.domain.Font; + +@Getter +@RequiredArgsConstructor +public class FontCreateRequestNotificationEvent { + private final Font font; + private final String phoneNumber; +} diff --git a/src/main/java/org/fontory/fontorybe/font/controller/FontController.java b/src/main/java/org/fontory/fontorybe/font/controller/FontController.java index e99fe3c..0987b73 100644 --- a/src/main/java/org/fontory/fontorybe/font/controller/FontController.java +++ b/src/main/java/org/fontory/fontorybe/font/controller/FontController.java @@ -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; @@ -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( @@ -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: {}", @@ -296,7 +273,7 @@ public ResponseEntity downloadFont( summary = "폰트 이름 중복 검사", description = "이름이 중복이면 true를 반환합니다." ) - @PostMapping("/verify-name") + @GetMapping("/verify-name") public ResponseEntity verifyFontName( @Login UserPrincipal userPrincipal, @RequestParam String fontName diff --git a/src/main/java/org/fontory/fontorybe/font/controller/dto/FontCreateDTO.java b/src/main/java/org/fontory/fontorybe/font/controller/dto/FontCreateDTO.java index 01a1a91..a5cbc75 100644 --- a/src/main/java/org/fontory/fontorybe/font/controller/dto/FontCreateDTO.java +++ b/src/main/java/org/fontory/fontorybe/font/controller/dto/FontCreateDTO.java @@ -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; @@ -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 = "휴대폰 번호 형식이 올바르지 않습니다.") diff --git a/src/main/java/org/fontory/fontorybe/font/controller/dto/FontProgressUpdateDTO.java b/src/main/java/org/fontory/fontorybe/font/controller/dto/FontProgressUpdateDTO.java index 2a26840..dbd43e5 100644 --- a/src/main/java/org/fontory/fontorybe/font/controller/dto/FontProgressUpdateDTO.java +++ b/src/main/java/org/fontory/fontorybe/font/controller/dto/FontProgressUpdateDTO.java @@ -1,6 +1,7 @@ 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; @@ -8,6 +9,7 @@ @Getter @Builder public class FontProgressUpdateDTO { - @Schema(description = "폰트의 상태 (PROGRESS, DONE)") + @NotNull(message = "폰트 상태는 필수입니다.") + @Schema(description = "폰트의 상태 (PROGRESS, DONE, FAILED)") private FontStatus status; } diff --git a/src/main/java/org/fontory/fontorybe/font/controller/dto/FontUpdateDTO.java b/src/main/java/org/fontory/fontorybe/font/controller/dto/FontUpdateDTO.java deleted file mode 100644 index 3e01b08..0000000 --- a/src/main/java/org/fontory/fontorybe/font/controller/dto/FontUpdateDTO.java +++ /dev/null @@ -1,11 +0,0 @@ -package org.fontory.fontorybe.font.controller.dto; - -import lombok.Builder; -import lombok.Getter; - -@Getter -@Builder -public class FontUpdateDTO { - private String name; - private String example; -} diff --git a/src/main/java/org/fontory/fontorybe/font/controller/port/FontService.java b/src/main/java/org/fontory/fontorybe/font/controller/port/FontService.java index 63e2dc8..eaa4e6f 100644 --- a/src/main/java/org/fontory/fontorybe/font/controller/port/FontService.java +++ b/src/main/java/org/fontory/fontorybe/font/controller/port/FontService.java @@ -9,7 +9,6 @@ public interface FontService { Font create(Long memberId, FontCreateDTO fontCreateDTO, FileUploadResult fileDetails); List getFontProgress(Long memberId); - FontUpdateResponse update(Long memberId, Long fontId, FontUpdateDTO fontUpdateDTO); Font getOrThrowById(Long id); Page getFonts(Long memberId, int page, int size); FontResponse getFont(Long fondId, Long memberId); diff --git a/src/main/java/org/fontory/fontorybe/font/domain/Font.java b/src/main/java/org/fontory/fontorybe/font/domain/Font.java index 3626303..5120156 100644 --- a/src/main/java/org/fontory/fontorybe/font/domain/Font.java +++ b/src/main/java/org/fontory/fontorybe/font/domain/Font.java @@ -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 @@ -22,6 +20,8 @@ public class Font { private String name; + private String engName; + private FontStatus status; private String example; @@ -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) @@ -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) @@ -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(); - } - } } diff --git a/src/main/java/org/fontory/fontorybe/font/infrastructure/entity/FontEntity.java b/src/main/java/org/fontory/fontorybe/font/infrastructure/entity/FontEntity.java index 4707eed..f6eaf03 100644 --- a/src/main/java/org/fontory/fontorybe/font/infrastructure/entity/FontEntity.java +++ b/src/main/java/org/fontory/fontorybe/font/infrastructure/entity/FontEntity.java @@ -31,6 +31,8 @@ public class FontEntity extends BaseEntity { private String name; + private String engName; + @Enumerated(EnumType.STRING) private FontStatus status; @@ -49,6 +51,7 @@ public Font toModel() { return Font.builder() .id(id) .name(name) + .engName(engName) .status(status) .example(example) .downloadCount(downloadCount) @@ -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()) diff --git a/src/main/java/org/fontory/fontorybe/font/service/FontServiceImpl.java b/src/main/java/org/fontory/fontorybe/font/service/FontServiceImpl.java index 958aa85..60c77e6 100644 --- a/src/main/java/org/fontory/fontorybe/font/service/FontServiceImpl.java +++ b/src/main/java/org/fontory/fontorybe/font/service/FontServiceImpl.java @@ -10,6 +10,8 @@ import org.fontory.fontorybe.file.application.port.FileService; import org.fontory.fontorybe.file.domain.FileMetadata; import org.fontory.fontorybe.file.domain.FileUploadResult; +import org.fontory.fontorybe.font.FontCreateCompleteNotificationEvent; +import org.fontory.fontorybe.font.FontCreateRequestNotificationEvent; import org.fontory.fontorybe.font.controller.dto.FontCreateDTO; import org.fontory.fontorybe.font.controller.dto.FontDeleteResponse; import org.fontory.fontorybe.font.controller.dto.FontDownloadResponse; @@ -17,7 +19,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; @@ -34,6 +35,7 @@ import org.fontory.fontorybe.member.domain.Member; import org.fontory.fontorybe.sms.application.port.PhoneNumberStorage; import org.fontory.fontorybe.sms.application.port.SmsService; +import org.springframework.context.ApplicationEventPublisher; import org.springframework.data.domain.Page; import org.springframework.data.domain.PageRequest; import org.springframework.data.domain.Sort; @@ -52,8 +54,7 @@ public class FontServiceImpl implements FontService { private final FontRequestProducer fontRequestProducer; private final CloudStorageService cloudStorageService; private final BadWordFiltering badWordFiltering; - private final SmsService smsService; - private final PhoneNumberStorage phoneNumberStorage; + private final ApplicationEventPublisher eventPublisher; @Override @Transactional @@ -65,7 +66,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()); @@ -74,8 +75,8 @@ public Font create(Long memberId, FontCreateDTO fontCreateDTO, FileUploadResult fontRequestProducer.sendFontRequest(FontRequestProduceDto.from(savedFont, member, fontPaperUrl)); if (fontCreateDTO.getPhoneNumber() != null && !fontCreateDTO.getPhoneNumber().isBlank()) { - phoneNumberStorage.savePhoneNumber(savedFont, fontCreateDTO.getPhoneNumber()); - smsService.sendFontCreationNotification(fontCreateDTO.getPhoneNumber(), fontCreateDTO.getName()); + String notificationPhoneNumber = fontCreateDTO.getPhoneNumber(); + eventPublisher.publishEvent(new FontCreateRequestNotificationEvent(savedFont, notificationPhoneNumber)); } log.info("Service completed: Font created with ID: {} and Font template image uploaded successfully", savedFont.getId()); @@ -97,23 +98,6 @@ public List 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) { @@ -316,16 +300,11 @@ 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) { - String phoneNumber = phoneNumberStorage.getPhoneNumber(targetFont); - - if (phoneNumber != null && !phoneNumber.isBlank()) { - smsService.sendFontProgressNotification(phoneNumber, updatedFont.getName()); - phoneNumberStorage.removePhoneNumber(targetFont); - } + eventPublisher.publishEvent(new FontCreateCompleteNotificationEvent(updatedFont)); } log.info("Service completed: Font ID: {} updated successfully", fontId); @@ -375,11 +354,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(); } } diff --git a/src/main/java/org/fontory/fontorybe/font/service/dto/FontRequestProduceDto.java b/src/main/java/org/fontory/fontorybe/font/service/dto/FontRequestProduceDto.java index 555919d..255fa9f 100644 --- a/src/main/java/org/fontory/fontorybe/font/service/dto/FontRequestProduceDto.java +++ b/src/main/java/org/fontory/fontorybe/font/service/dto/FontRequestProduceDto.java @@ -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; @@ -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")) diff --git a/src/main/java/org/fontory/fontorybe/member/controller/MemberController.java b/src/main/java/org/fontory/fontorybe/member/controller/MemberController.java index 08e7a44..daf2fc2 100644 --- a/src/main/java/org/fontory/fontorybe/member/controller/MemberController.java +++ b/src/main/java/org/fontory/fontorybe/member/controller/MemberController.java @@ -36,10 +36,8 @@ public ResponseEntity getInfoMember( log.info("Request received: Get member info ID: {} by member ID: {}", id, requestMemberId); Member targetMember = memberLookupService.getOrThrowById(id); - String fileUrl = cloudStorageService.getProfileImageUrl(targetMember.getProfileImageKey()); - log.info("ProfileImageUrl generated : {}", fileUrl); - ProfileResponse profileResponse = ProfileResponse.from(targetMember, fileUrl); + ProfileResponse profileResponse = ProfileResponse.from(targetMember); log.info("Response sent: ProfileResponse : {}", profileResponse); return ResponseEntity diff --git a/src/main/java/org/fontory/fontorybe/member/controller/ProfileController.java b/src/main/java/org/fontory/fontorybe/member/controller/ProfileController.java index b651cee..4d55230 100644 --- a/src/main/java/org/fontory/fontorybe/member/controller/ProfileController.java +++ b/src/main/java/org/fontory/fontorybe/member/controller/ProfileController.java @@ -3,6 +3,7 @@ import io.swagger.v3.oas.annotations.Operation; import io.swagger.v3.oas.annotations.tags.Tag; import jakarta.servlet.http.HttpServletResponse; +import jakarta.validation.Valid; import lombok.Builder; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; @@ -19,6 +20,8 @@ import org.fontory.fontorybe.member.controller.port.MemberLookupService; import org.fontory.fontorybe.member.controller.port.MemberUpdateService; import org.fontory.fontorybe.member.domain.Member; +import org.fontory.fontorybe.member.domain.exception.MemberNotFoundException; +import org.fontory.fontorybe.member.infrastructure.entity.MemberStatus; import org.springframework.http.HttpStatus; import org.springframework.http.ResponseEntity; import org.springframework.web.bind.annotation.*; @@ -48,15 +51,21 @@ public class ProfileController { ) @GetMapping public ResponseEntity getMyProfile( - @Login UserPrincipal me) { + @Login(required = false) UserPrincipal me) { + if (me == null) { + log.info("Request received: getMyInfo - no login"); + throw new MemberNotFoundException(); + } Long requestMemberId = me.getId(); log.info("Request received: getMyInfo member ID: {}", requestMemberId); Member lookupMember = memberLookupService.getOrThrowById(requestMemberId); - String fileUrl = cloudStorageService.getProfileImageUrl(lookupMember.getProfileImageKey()); - log.info("ProfileImageUrl generated : {}", fileUrl); + if (lookupMember.getStatus().equals(MemberStatus.ONBOARDING)) { + log.info("Request received: getMyInfo - member is onboarding"); + throw new MemberNotFoundException(); + } - MyProfileResponse myProfileResponse = MyProfileResponse.from(lookupMember, fileUrl); + MyProfileResponse myProfileResponse = MyProfileResponse.from(lookupMember); log.info("Response sent: MyProfileDto : {}", myProfileResponse); return ResponseEntity @@ -68,25 +77,19 @@ public ResponseEntity getMyProfile( @Operation( summary = "내정보 수정" ) - @PatchMapping(consumes = MULTIPART_FORM_DATA_VALUE) + @PatchMapping public ResponseEntity updateMember( @Login UserPrincipal userPrincipal, - @RequestPart MemberUpdateRequest req, - @SingleFileUpload @RequestPart("file") List files + @RequestBody @Valid MemberUpdateRequest req ) { Long requestMemberId = userPrincipal.getId(); - MultipartFile file = extractSingleMultipartFile(files); - log.info("Request received: update member ID: {} with request: {}", requestMemberId, req); - logFileDetails(file, "Member profile image upload"); - FileUploadResult fileUploadResult = fileService.uploadProfileImage(file, requestMemberId); Member updatedMember = memberUpdateService.update(requestMemberId, req); - log.info("Updated : Member ID: {} Updated successfully with nickname: {}, terms : {}", - updatedMember.getId(), updatedMember.getNickname(), updatedMember.getTerms()); + log.info("Updated : Member ID: {} Updated successfully with nickname: {}", updatedMember.getId(), updatedMember.getNickname()); - MyProfileResponse myProfileResponse = MyProfileResponse.from(updatedMember, fileUploadResult.getFileUrl()); + MyProfileResponse myProfileResponse = MyProfileResponse.from(updatedMember); log.info("Response sent: MyProfileDto : {}", myProfileResponse); return ResponseEntity diff --git a/src/main/java/org/fontory/fontorybe/member/controller/RegistrationController.java b/src/main/java/org/fontory/fontorybe/member/controller/RegistrationController.java index 3d054b2..a6a2ac4 100644 --- a/src/main/java/org/fontory/fontorybe/member/controller/RegistrationController.java +++ b/src/main/java/org/fontory/fontorybe/member/controller/RegistrationController.java @@ -2,11 +2,13 @@ import io.swagger.v3.oas.annotations.Operation; import io.swagger.v3.oas.annotations.tags.Tag; +import jakarta.validation.Valid; import lombok.Builder; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; import org.fontory.fontorybe.authentication.adapter.inbound.annotation.Login; import org.fontory.fontorybe.authentication.domain.UserPrincipal; +import org.fontory.fontorybe.file.application.port.CloudStorageService; import org.fontory.fontorybe.file.application.port.FileService; import org.fontory.fontorybe.file.domain.FileUploadResult; import org.fontory.fontorybe.file.application.annotation.SingleFileUpload; @@ -17,6 +19,7 @@ import org.fontory.fontorybe.member.domain.Member; import org.springframework.http.HttpStatus; import org.springframework.http.ResponseEntity; +import org.springframework.security.core.parameters.P; import org.springframework.web.bind.annotation.*; import org.springframework.web.multipart.MultipartFile; @@ -32,6 +35,7 @@ @RequestMapping("/register") @Tag(name = "사용자 - 신규", description = "회원가입/온보딩") public class RegistrationController { + private final CloudStorageService cloudStorageService; private final MemberLookupService memberLookupService; private final MemberOnboardService memberOnboardService; private final FileService fileService; @@ -55,36 +59,22 @@ public ResponseEntity checkDuplicate( @Operation( summary = "회원가입" ) - @PostMapping(consumes = MULTIPART_FORM_DATA_VALUE) + @PostMapping public ResponseEntity register( @Login UserPrincipal user, - @RequestPart InitMemberInfoRequest req, - @SingleFileUpload @RequestPart("file") List files + @RequestBody @Valid InitMemberInfoRequest req ) { Long requestMemberId = user.getId(); - MultipartFile file = extractSingleMultipartFile(files); - log.info("Request received: Create member ID: {} with request: {}", requestMemberId, req); - logFileDetails(file, "Member profile image upload"); - FileUploadResult fileUploadResult = fileService.uploadProfileImage(file, requestMemberId); - Member updatedMember = memberOnboardService.initNewMemberInfo(requestMemberId, req, fileUploadResult); + Member updatedMember = memberOnboardService.initNewMemberInfo(requestMemberId, req); log.info("Response sent: Member ID: {} Created successfully with nickname: {}", updatedMember.getId(), updatedMember.getNickname()); return ResponseEntity .status(HttpStatus.CREATED) - .body(MemberCreateResponse.from(updatedMember, fileUploadResult.getFileUrl())); - } - - 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()); + .body(MemberCreateResponse.from(updatedMember)); } } diff --git a/src/main/java/org/fontory/fontorybe/member/controller/dto/InitMemberInfoRequest.java b/src/main/java/org/fontory/fontorybe/member/controller/dto/InitMemberInfoRequest.java index 3bb9513..9217ebb 100644 --- a/src/main/java/org/fontory/fontorybe/member/controller/dto/InitMemberInfoRequest.java +++ b/src/main/java/org/fontory/fontorybe/member/controller/dto/InitMemberInfoRequest.java @@ -1,5 +1,9 @@ package org.fontory.fontorybe.member.controller.dto; +import jakarta.validation.constraints.NotBlank; +import jakarta.validation.constraints.NotNull; +import jakarta.validation.constraints.Past; +import jakarta.validation.constraints.Size; import java.time.LocalDate; import lombok.AllArgsConstructor; @@ -13,8 +17,14 @@ @ToString @AllArgsConstructor public class InitMemberInfoRequest { + @NotBlank(message = "닉네임은 필수 입력 값입니다.") + @Size(min = 2, max = 20, message = "닉네임은 2자 이상 20자 이하로 입력해주세요.") private String nickname; + + @NotNull(message = "성별을 선택해주세요.") private Gender gender; + + @NotNull(message = "생년월일을 입력해주세요.") + @Past(message = "생년월일은 과거 날짜만 가능합니다.") private LocalDate birth; - private Boolean terms; } diff --git a/src/main/java/org/fontory/fontorybe/member/controller/dto/MemberCreateResponse.java b/src/main/java/org/fontory/fontorybe/member/controller/dto/MemberCreateResponse.java index 510988c..1f22fce 100644 --- a/src/main/java/org/fontory/fontorybe/member/controller/dto/MemberCreateResponse.java +++ b/src/main/java/org/fontory/fontorybe/member/controller/dto/MemberCreateResponse.java @@ -13,18 +13,14 @@ public class MemberCreateResponse { private final String nickname; private final Gender gender; - private final String profileImageUrl; private final LocalDate birth; - private final boolean terms; private final LocalDateTime createdAt; - public static MemberCreateResponse from(Member member, String url) { + public static MemberCreateResponse from(Member member) { return MemberCreateResponse.builder() .nickname(member.getNickname()) .gender(member.getGender()) - .profileImageUrl(url) .birth(member.getBirth()) - .terms(member.getTerms()) .createdAt(member.getCreatedAt()) .build(); } diff --git a/src/main/java/org/fontory/fontorybe/member/controller/dto/MemberUpdateRequest.java b/src/main/java/org/fontory/fontorybe/member/controller/dto/MemberUpdateRequest.java index 63179cd..3a9780a 100644 --- a/src/main/java/org/fontory/fontorybe/member/controller/dto/MemberUpdateRequest.java +++ b/src/main/java/org/fontory/fontorybe/member/controller/dto/MemberUpdateRequest.java @@ -1,5 +1,8 @@ package org.fontory.fontorybe.member.controller.dto; +import jakarta.validation.constraints.NotBlank; +import jakarta.validation.constraints.NotNull; +import jakarta.validation.constraints.Size; import lombok.AllArgsConstructor; import lombok.Builder; import lombok.Getter; @@ -10,6 +13,8 @@ @ToString @AllArgsConstructor public class MemberUpdateRequest { + @NotBlank(message = "닉네임은 필수 입력 값입니다.") + @Size(min = 2, max = 20, message = "닉네임은 2자 이상 20자 이하로 입력해주세요.") private String nickname; - private Boolean terms; } + diff --git a/src/main/java/org/fontory/fontorybe/member/controller/dto/MemberUpdateResponse.java b/src/main/java/org/fontory/fontorybe/member/controller/dto/MemberUpdateResponse.java deleted file mode 100644 index 676718f..0000000 --- a/src/main/java/org/fontory/fontorybe/member/controller/dto/MemberUpdateResponse.java +++ /dev/null @@ -1,25 +0,0 @@ -package org.fontory.fontorybe.member.controller.dto; - -import lombok.Builder; -import lombok.Getter; -import org.fontory.fontorybe.member.domain.Member; - -import java.time.LocalDateTime; - -@Getter -@Builder -public class MemberUpdateResponse { - private String nickname; - private String profileImage; - private Boolean terms; - private LocalDateTime updatedAt; - - public static MemberUpdateResponse from(Member member) { - return MemberUpdateResponse.builder() - .nickname(member.getNickname()) - .profileImage(member.getProfileImageKey()) - .terms(member.getTerms()) - .updatedAt(member.getUpdatedAt()) - .build(); - } -} diff --git a/src/main/java/org/fontory/fontorybe/member/controller/dto/MyProfileResponse.java b/src/main/java/org/fontory/fontorybe/member/controller/dto/MyProfileResponse.java index f396acc..12f8b82 100644 --- a/src/main/java/org/fontory/fontorybe/member/controller/dto/MyProfileResponse.java +++ b/src/main/java/org/fontory/fontorybe/member/controller/dto/MyProfileResponse.java @@ -12,25 +12,15 @@ @Builder @ToString public class MyProfileResponse { - private Long memberId; private String nickname; private Gender gender; private LocalDate birth; - private boolean terms; - private String profileImageUrl; - public static MyProfileResponse from(Member member, String url) { + public static MyProfileResponse from(Member member) { return MyProfileResponse.builder() - .memberId(member.getId()) .nickname(member.getNickname()) .birth(member.getBirth()) .gender(member.getGender()) - .terms(member.getTerms()) - .profileImageUrl(url) .build(); } - - public boolean getTerms() { - return this.terms; - } } diff --git a/src/main/java/org/fontory/fontorybe/member/controller/dto/ProfileResponse.java b/src/main/java/org/fontory/fontorybe/member/controller/dto/ProfileResponse.java index 96b0336..596f044 100644 --- a/src/main/java/org/fontory/fontorybe/member/controller/dto/ProfileResponse.java +++ b/src/main/java/org/fontory/fontorybe/member/controller/dto/ProfileResponse.java @@ -11,13 +11,11 @@ public class ProfileResponse { private Long memberId; private String nickname; - private String profileImageUrl; - public static ProfileResponse from(Member member, String url) { + public static ProfileResponse from(Member member) { return ProfileResponse.builder() .memberId(member.getId()) .nickname(member.getNickname()) - .profileImageUrl(url) .build(); } } diff --git a/src/main/java/org/fontory/fontorybe/member/controller/port/MemberOnboardService.java b/src/main/java/org/fontory/fontorybe/member/controller/port/MemberOnboardService.java index 8441560..ee48e88 100644 --- a/src/main/java/org/fontory/fontorybe/member/controller/port/MemberOnboardService.java +++ b/src/main/java/org/fontory/fontorybe/member/controller/port/MemberOnboardService.java @@ -7,5 +7,5 @@ public interface MemberOnboardService { Member fetchOrCreateMember(Provide p); - Member initNewMemberInfo(Long requestMemberId, InitMemberInfoRequest initMemberInfoRequest, FileUploadResult fileUploadResult); + Member initNewMemberInfo(Long requestMemberId, InitMemberInfoRequest initMemberInfoRequest); } diff --git a/src/main/java/org/fontory/fontorybe/member/controller/port/MemberUpdateService.java b/src/main/java/org/fontory/fontorybe/member/controller/port/MemberUpdateService.java index 0ca979c..21423e0 100644 --- a/src/main/java/org/fontory/fontorybe/member/controller/port/MemberUpdateService.java +++ b/src/main/java/org/fontory/fontorybe/member/controller/port/MemberUpdateService.java @@ -5,6 +5,5 @@ public interface MemberUpdateService { Member update(Long requestMemberId, MemberUpdateRequest memberUpdateRequest); - Member setProfileImageKey(Member requetMember, String profileImageKey); Member disable(Long requestMemberId); } diff --git a/src/main/java/org/fontory/fontorybe/member/domain/Member.java b/src/main/java/org/fontory/fontorybe/member/domain/Member.java index dd1d166..d4750ac 100644 --- a/src/main/java/org/fontory/fontorybe/member/domain/Member.java +++ b/src/main/java/org/fontory/fontorybe/member/domain/Member.java @@ -23,10 +23,6 @@ public class Member { private LocalDate birth; - private boolean terms; - - private String profileImageKey; - private LocalDateTime createdAt; private LocalDateTime updatedAt; @@ -42,21 +38,17 @@ public static Member fromDefaults(MemberDefaults memberDefaults, String nickname .nickname(nickname) .gender(memberDefaults.getGender()) .birth(memberDefaults.getBirth()) - .terms(memberDefaults.getTerms()) - .profileImageKey(memberDefaults.getProfileImageKey()) .provideId(provide.getId()) .status(MemberStatus.ONBOARDING) .build(); } - public Member initNewMemberInfo(InitMemberInfoRequest initNewMemberInfo, String profileImageKey) { + public Member initNewMemberInfo(InitMemberInfoRequest initNewMemberInfo) { return Member.builder() .id(this.id) .nickname(initNewMemberInfo.getNickname()) .gender(initNewMemberInfo.getGender()) .birth(initNewMemberInfo.getBirth()) - .terms(initNewMemberInfo.getTerms()) - .profileImageKey(profileImageKey) .createdAt(this.createdAt) .provideId(this.provideId) .deletedAt(this.deletedAt) @@ -69,7 +61,6 @@ public Member update(MemberUpdateRequest memberUpdateRequest) { return Member.builder() //tobe update .nickname(memberUpdateRequest.getNickname()) - .terms(memberUpdateRequest.getTerms()) //not to be update .id(this.id) @@ -80,32 +71,10 @@ public Member update(MemberUpdateRequest memberUpdateRequest) { .deletedAt(this.deletedAt) .provideId(this.provideId) .status(this.status) - .profileImageKey(this.profileImageKey) .build(); } public void disable() { this.status = MemberStatus.DEACTIVATE; this.deletedAt = LocalDateTime.now(); } - - public boolean getTerms() { - return this.terms; - } - - public Member setProfileImageKey(String profileImageKey) { - return Member.builder() - .profileImageKey(profileImageKey) - - .id(this.id) - .nickname(this.nickname) - .gender(this.gender) - .birth(this.birth) - .createdAt(this.createdAt) - .provideId(this.provideId) - .deletedAt(this.deletedAt) - .terms(this.terms) - .provideId(this.provideId) - .status(this.status) - .build(); - } } diff --git a/src/main/java/org/fontory/fontorybe/member/domain/MemberDefaults.java b/src/main/java/org/fontory/fontorybe/member/domain/MemberDefaults.java index b9ff27f..1bdb16d 100644 --- a/src/main/java/org/fontory/fontorybe/member/domain/MemberDefaults.java +++ b/src/main/java/org/fontory/fontorybe/member/domain/MemberDefaults.java @@ -13,22 +13,11 @@ @ConfigurationProperties(prefix="member.default") public class MemberDefaults { private LocalDate birth; - private boolean termsAgree; - private String profileImageKey; private Gender gender; @ConstructorBinding - public MemberDefaults(LocalDate birth, - boolean termsAgree, - String profileImageKey) { + public MemberDefaults(LocalDate birth) { this.birth = birth; - this.termsAgree = termsAgree; - this.profileImageKey = profileImageKey; this.gender = Gender.NONE; } - - public boolean getTerms() { - return this.termsAgree; - } - } diff --git a/src/main/java/org/fontory/fontorybe/member/infrastructure/entity/MemberEntity.java b/src/main/java/org/fontory/fontorybe/member/infrastructure/entity/MemberEntity.java index 8fe3678..56b7f55 100644 --- a/src/main/java/org/fontory/fontorybe/member/infrastructure/entity/MemberEntity.java +++ b/src/main/java/org/fontory/fontorybe/member/infrastructure/entity/MemberEntity.java @@ -36,10 +36,6 @@ public class MemberEntity extends BaseEntity { private LocalDate birth; - private Boolean terms; - - private String profileImageKey; - private Long provideId; @Enumerated(EnumType.STRING) @@ -53,8 +49,6 @@ public Member toModel() { .nickname(nickname) .gender(gender) .birth(birth) - .terms(terms) - .profileImageKey(profileImageKey) .provideId(provideId) .status(status) .createdAt(getCreatedAt()) @@ -69,8 +63,6 @@ public static MemberEntity from(Member member) { .nickname(member.getNickname()) .gender(member.getGender()) .birth(member.getBirth()) - .terms(member.getTerms()) - .profileImageKey(member.getProfileImageKey()) .provideId(member.getProvideId()) .status(member.getStatus()) .createdAt(member.getCreatedAt()) diff --git a/src/main/java/org/fontory/fontorybe/member/service/MemberOnboardServiceImpl.java b/src/main/java/org/fontory/fontorybe/member/service/MemberOnboardServiceImpl.java index 07c615f..b189b7c 100644 --- a/src/main/java/org/fontory/fontorybe/member/service/MemberOnboardServiceImpl.java +++ b/src/main/java/org/fontory/fontorybe/member/service/MemberOnboardServiceImpl.java @@ -43,10 +43,8 @@ public Member fetchOrCreateMember(Provide p) { @Override @Transactional public Member initNewMemberInfo(Long requestMemberId, - InitMemberInfoRequest initNewMemberInfoRequest, - FileUploadResult fileUploadResult) { + InitMemberInfoRequest initNewMemberInfoRequest) { Member targetMember = memberLookupService.getOrThrowById(requestMemberId); - FileMetadata fileMetadata = fileService.getOrThrowById(fileUploadResult.getId()); if (targetMember.getStatus() == MemberStatus.ACTIVATE) { throw new MemberAlreadyJoinedException(); } else if (memberLookupService.existsByNickname(initNewMemberInfoRequest.getNickname())) { @@ -55,7 +53,7 @@ public Member initNewMemberInfo(Long requestMemberId, checkContainsBadWord(initNewMemberInfoRequest.getNickname()); - return memberRepository.save(targetMember.initNewMemberInfo(initNewMemberInfoRequest, fileMetadata.getKey())); + return memberRepository.save(targetMember.initNewMemberInfo(initNewMemberInfoRequest)); } private void checkContainsBadWord(String nickname) { diff --git a/src/main/java/org/fontory/fontorybe/member/service/MemberUpdateServiceImpl.java b/src/main/java/org/fontory/fontorybe/member/service/MemberUpdateServiceImpl.java index e40b866..21afb92 100644 --- a/src/main/java/org/fontory/fontorybe/member/service/MemberUpdateServiceImpl.java +++ b/src/main/java/org/fontory/fontorybe/member/service/MemberUpdateServiceImpl.java @@ -42,13 +42,6 @@ public Member update(Long requestMemberId, MemberUpdateRequest memberUpdateReque return memberRepository.save(targetMember.update(memberUpdateRequest)); } - @Override - @Transactional - public Member setProfileImageKey(Member requetMember, String profileImageKey) { - Member member = requetMember.setProfileImageKey(profileImageKey); - return memberRepository.save(member); - } - @Override @Transactional public Member disable(Long requestMemberId) { diff --git a/src/main/java/org/fontory/fontorybe/sms/application/SmsServiceImpl.java b/src/main/java/org/fontory/fontorybe/sms/application/SmsServiceImpl.java index 0e7b430..e703b14 100644 --- a/src/main/java/org/fontory/fontorybe/sms/application/SmsServiceImpl.java +++ b/src/main/java/org/fontory/fontorybe/sms/application/SmsServiceImpl.java @@ -15,7 +15,7 @@ public class SmsServiceImpl implements SmsService { @Value("${coolsms.phone-number}") - private String phoneNumber; + private String fromPhoneNumber; private final DefaultMessageService messageService; @@ -23,25 +23,25 @@ public class SmsServiceImpl implements SmsService { private static final String FONT_PROGRESS_MESSAGE_FORMAT = "[Fontory]\n\"%s\" 폰트 제작이 완료되었습니다."; @Override - public void sendFontCreationNotification(String to, String fontName) { + public void sendFontCreateRequestNotification(String to, String fontName) { sendSms(to, String.format(FONT_CREATION_MESSAGE_FORMAT, fontName)); } @Override - public void sendFontProgressNotification(String to, String fontName) { + public void sendFontCreateCompleteNotification(String to, String fontName) { sendSms(to, String.format(FONT_PROGRESS_MESSAGE_FORMAT, fontName)); } - private void sendSms(String to, String text) { - if (to == null || to.isBlank()) { + private void sendSms(String toPhoneNumber, String content) { + if (toPhoneNumber == null || toPhoneNumber.isBlank()) { log.warn("Service warning: recipient phone number is empty"); return; } Message message = new Message(); - message.setFrom(phoneNumber); - message.setTo(to); - message.setText(text); + message.setFrom(fromPhoneNumber); + message.setTo(toPhoneNumber); + message.setText(content); messageService.sendOne(new SingleMessageSendingRequest(message)); } diff --git a/src/main/java/org/fontory/fontorybe/sms/application/port/SmsService.java b/src/main/java/org/fontory/fontorybe/sms/application/port/SmsService.java index 408229d..9dac948 100644 --- a/src/main/java/org/fontory/fontorybe/sms/application/port/SmsService.java +++ b/src/main/java/org/fontory/fontorybe/sms/application/port/SmsService.java @@ -1,6 +1,6 @@ package org.fontory.fontorybe.sms.application.port; public interface SmsService { - void sendFontCreationNotification(String to, String fontName); - void sendFontProgressNotification(String to, String fontName); + void sendFontCreateRequestNotification(String to, String fontName); + void sendFontCreateCompleteNotification(String to, String fontName); } diff --git a/src/main/resources/application-prod.properties b/src/main/resources/application-prod.properties index 9351369..c593eef 100644 --- a/src/main/resources/application-prod.properties +++ b/src/main/resources/application-prod.properties @@ -1,3 +1,3 @@ -spring.jpa.hibernate.ddl-auto=create +spring.jpa.hibernate.ddl-auto=update cookies.domain=.fontory.co.kr diff --git a/src/main/resources/application.properties b/src/main/resources/application.properties index 1ad54b1..fcc6af4 100644 --- a/src/main/resources/application.properties +++ b/src/main/resources/application.properties @@ -32,5 +32,9 @@ jwt.refresh-token-validity-ms=604800000 member.default.birth=1999-12-31 member.default.profile-image-key=default -member.default.terms-agree=false + +# max file size +spring.servlet.multipart.maxFileSize=5MB +# max total file size +spring.servlet.multipart.maxRequestSize=10MB diff --git a/src/test/java/org/fontory/fontorybe/TestConstants.java b/src/test/java/org/fontory/fontorybe/TestConstants.java index a96bde7..4a1d60b 100644 --- a/src/test/java/org/fontory/fontorybe/TestConstants.java +++ b/src/test/java/org/fontory/fontorybe/TestConstants.java @@ -11,7 +11,6 @@ private TestConstants() {} // 인스턴스 생성 방지 // NOT created in SQL public static final Gender NEW_MEMBER_GENDER = Gender.FEMALE; - public static final boolean NEW_MEMBER_TERMS = false; public static final LocalDate NEW_MEMBER_BIRTH = LocalDate.of(2025, 1, 22); public static final String NEW_MEMBER_NICKNAME = "newMemberNickName"; public static final String NEW_MEMBER_PROFILE_KEY = "newMemberProfileImage"; @@ -23,7 +22,6 @@ private TestConstants() {} // 인스턴스 생성 방지 public static final String DEFAULT_PROFILE_KEY = "defaultProfileImage"; // Created in SQL public static final Gender TEST_MEMBER_GENDER = Gender.MALE; - public static final boolean TEST_MEMBER_TERMS = true; public static final LocalDate TEST_MEMBER_BIRTH = LocalDate.of(2025, 1, 26); public static final String TEST_MEMBER_NICKNAME = "testMemberNickName"; public static final String TEST_MEMBER_PROFILE_KEY = "testMemberProfileImage"; @@ -36,7 +34,6 @@ private TestConstants() {} // 인스턴스 생성 방지 public static final Long TEST_PROVIDE_ID = 1L; public static final Long NON_EXIST_ID = -1L; - public static final boolean UPDATE_MEMBER_TERMS = Boolean.FALSE; public static final String UPDATE_MEMBER_NICKNAME = "updateMemberNickName"; public static final String UPDATE_MEMBER_PROFILE_KEY= "updateMemberProfileImage"; diff --git a/src/test/java/org/fontory/fontorybe/integration/file/FileServiceIntegrationTest.java b/src/test/java/org/fontory/fontorybe/integration/file/FileServiceIntegrationTest.java index d2a7cc1..394a7b1 100644 --- a/src/test/java/org/fontory/fontorybe/integration/file/FileServiceIntegrationTest.java +++ b/src/test/java/org/fontory/fontorybe/integration/file/FileServiceIntegrationTest.java @@ -57,23 +57,6 @@ void setup() { given(s3Client.deleteObject(any(DeleteObjectRequest.class))) .willReturn(DeleteObjectResponse.builder().build()); - // Stub cloud storage upload for profile image - given(cloudStorageService.uploadProfileImage(any(FileCreate.class), anyString())) - .willAnswer(invocation -> { - FileCreate fc = invocation.getArgument(0); - String key = invocation.getArgument(1); - return FileMetadata.builder() - .fileName(fc.getFileName()) - .fileType(fc.getFileType()) - .extension(fc.getExtension()) - .key(key) - .uploaderId(fc.getUploaderId()) - .size(fc.getFile().getSize()) - .uploadedAt(LocalDateTime.now()) - .createdAt(LocalDateTime.now()) - .updatedAt(LocalDateTime.now()) - .build(); - }); // Stub cloud storage upload for font template given(cloudStorageService.uploadFontTemplateImage(any(FileCreate.class))) .willAnswer(invocation -> { @@ -91,10 +74,8 @@ void setup() { .updatedAt(LocalDateTime.now()) .build(); }); - // Stub getting file URL - given(cloudStorageService.getProfileImageUrl(anyString())) - .willReturn(mockedFileUrl); + // Stub getting file URL given(cloudStorageService.getFontPaperUrl(anyString())) .willReturn(mockedFileUrl); } @@ -116,30 +97,6 @@ void getNonExistentFileMetadataTest() { .isInstanceOf(FileNotFoundException.class); } - @Test - @DisplayName("uploadProfileImage - uploads successfully and updates member") - void uploadProfileImageTest() { - MockMultipartFile mockFile = createMockImageFile("profileTest.jpg", "image/jpeg"); - - FileUploadResult result = fileService.uploadProfileImage(mockFile, existMemberId); - - assertThat(result).isNotNull(); - assertThat(result.getFileUrl()).isEqualTo(mockedFileUrl); - assertThat(result.getFileName()).isEqualTo(existMemberId + ".jpg"); - assertThat(result.getSize()).isEqualTo(mockFile.getSize()); - - Member member = memberLookupService.getOrThrowById(existMemberId); - assertThat(member.getProfileImageKey()).isNotNull(); - } - - @Test - @DisplayName("uploadProfileImage - non-existent member throws") - void uploadProfileImageNonExistentMemberTest() { - MockMultipartFile mockFile = createMockImageFile("profileTest.jpg", "image/jpeg"); - assertThatThrownBy(() -> fileService.uploadProfileImage(mockFile, nonExistentId)) - .isInstanceOf(MemberNotFoundException.class); - } - @Test @DisplayName("uploadFontTemplateImage - uploads successfully") void uploadFontTemplateImageTest() { diff --git a/src/test/java/org/fontory/fontorybe/integration/font/FontControllerIntegrationTest.java b/src/test/java/org/fontory/fontorybe/integration/font/FontControllerIntegrationTest.java index 2eb3a9f..b209b41 100644 --- a/src/test/java/org/fontory/fontorybe/integration/font/FontControllerIntegrationTest.java +++ b/src/test/java/org/fontory/fontorybe/integration/font/FontControllerIntegrationTest.java @@ -18,7 +18,6 @@ import com.fasterxml.jackson.databind.ObjectMapper; import java.nio.charset.StandardCharsets; -import java.util.UUID; import jakarta.servlet.http.Cookie; import org.fontory.fontorybe.authentication.application.port.JwtTokenProvider; @@ -30,7 +29,6 @@ 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; import org.fontory.fontorybe.font.service.port.FontRequestProducer; import org.junit.jupiter.api.BeforeEach; @@ -39,6 +37,7 @@ import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc; import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.context.ApplicationEventPublisher; import org.springframework.http.MediaType; import org.springframework.mock.web.MockMultipartFile; import org.springframework.test.context.bean.override.mockito.MockitoBean; @@ -68,6 +67,8 @@ class FontControllerIntegrationTest { private FileService fileService; @MockitoBean private FontRequestProducer fontRequestProducer; + @MockitoBean + private ApplicationEventPublisher eventPublisher; private final Long existMemberId = 999L; private final String existMemberName = "existMemberNickName"; @@ -83,7 +84,8 @@ class FontControllerIntegrationTest { private final String existFontKey = "key"; private final String existFontTemplateExtension = "jpg"; - private final String newFontName = "newFontName"; + private final String newFontName = "제작한글폰트1"; + private final String newFontEngName = "newFontEngName"; private final String newFontExample = "newFontExample"; private final String updateFontName = "updateFontName"; @@ -127,6 +129,7 @@ void addFontSuccess() throws Exception { // given FontCreateDTO createDTO = FontCreateDTO.builder() .name(newFontName) + .engName(newFontEngName) .example(newFontExample) .build(); @@ -203,51 +206,6 @@ void getFontProgressWithoutAuthHeader() throws Exception { .andExpect(jsonPath("$.errorMessage").value("Authentication Required.")); } - @Test - @DisplayName("PUT /fonts/{fontId} - update font success with valid Authorization header") - void updateFontSuccess() throws Exception { - // given - FontUpdateDTO updateDTO = FontUpdateDTO.builder() - .name(updateFontName) - .example(updateFontExample) - .build(); - - String jsonRequest = objectMapper.writeValueAsString(updateDTO); - - // when & then - mockMvc.perform(put("/fonts/{fontId}", existFontId) - .cookie(new Cookie("accessToken", validAccessToken)) - .contentType(MediaType.APPLICATION_JSON) - .content(jsonRequest)) - .andExpect(status().isOk()) - .andExpect(jsonPath("$.id", is(existFontId.intValue()))) - .andExpect(jsonPath("$.name", is(updateFontName))) - .andExpect(jsonPath("$.status").isNotEmpty()) - .andExpect(jsonPath("$.example", is(updateFontExample))) - .andExpect(jsonPath("$.memberId").isNotEmpty()) - .andExpect(jsonPath("$.createdAt").isNotEmpty()); - } - - @Test - @DisplayName("PUT /fonts/{fontId} - update font without Authorization header returns 401") - void updateFontWithoutAuthHeader() throws Exception { - // given - FontUpdateDTO updateDTO = FontUpdateDTO.builder() - .name(updateFontName) - .example(updateFontExample) - .build(); - - String jsonRequest = objectMapper.writeValueAsString(updateDTO); - - // when & then - mockMvc.perform(put("/fonts/{fontId}", existFontId) - .contentType(MediaType.APPLICATION_JSON) - .content(jsonRequest)) - .andExpect(status().isUnauthorized()) - .andExpect(content().contentType("application/json;charset=UTF-8")) - .andExpect(jsonPath("$.errorMessage").value("Authentication Required.")); - } - @Test @DisplayName("GET /fonts/members - success with valid Authorization header") void getMyFontsSuccess() throws Exception { diff --git a/src/test/java/org/fontory/fontorybe/integration/font/FontServiceIntegrationTest.java b/src/test/java/org/fontory/fontorybe/integration/font/FontServiceIntegrationTest.java index 6844014..9a124c9 100644 --- a/src/test/java/org/fontory/fontorybe/integration/font/FontServiceIntegrationTest.java +++ b/src/test/java/org/fontory/fontorybe/integration/font/FontServiceIntegrationTest.java @@ -28,6 +28,8 @@ import org.junit.jupiter.api.Test; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.boot.test.mock.mockito.MockBean; +import org.springframework.context.ApplicationEventPublisher; import org.springframework.data.domain.Page; import org.springframework.test.context.bean.override.mockito.MockitoBean; import org.springframework.test.context.jdbc.Sql; @@ -43,6 +45,8 @@ class FontServiceIntegrationTest { private FileService fileService; @MockitoBean private FontRequestProducer fontRequestProducer; + @MockitoBean + private ApplicationEventPublisher eventPublisher; private final Long existMemberId = 999L; private final String existMemberName = "existMemberNickName"; @@ -93,6 +97,7 @@ void createFontSuccess() { // given FontCreateDTO dto = FontCreateDTO.builder() .name("생성폰트") + .engName("ENG1") .example("생성 폰트 예제입니다.") .build(); @@ -122,6 +127,7 @@ void getFontProgressSuccess() { existMemberId, FontCreateDTO.builder() .name("진행중폰트" + i) + .engName("ENG" + i) .example("예제" + i) .build(), fileDetails @@ -138,47 +144,6 @@ void getFontProgressSuccess() { result.forEach(font -> assertThat(font.getStatus()).isEqualTo(FontStatus.PROGRESS)); } - @Test - @DisplayName("font - update success test") - void updateFontSuccess() { - // given - FontUpdateDTO dto = FontUpdateDTO.builder() - .name("수정폰트") - .example("수정 폰트 예시입니다.") - .build(); - - // when - FontUpdateResponse updated = fontService.update(existMemberId, existFontId, dto); - - // then - assertAll( - () -> assertThat(updated.getId()).isEqualTo(existFontId), - () -> assertThat(updated.getName()).isEqualTo("수정폰트"), - () -> assertThat(updated.getExample()).isEqualTo("수정 폰트 예시입니다.") - ); - } - - @Test - @DisplayName("font - update fail test caused by access denied") - void updateFontAccessDeniedFail() { - // given - FontCreateDTO createDTO = FontCreateDTO.builder() - .name("다른사람폰트") - .example("다른예제") - .build(); - - Font elseFont = fontService.create(createdMemberId, createDTO, fileDetails); - - FontUpdateDTO updateDTO = FontUpdateDTO.builder() - .name("수정시도") - .example("예제수정") - .build(); - - // when & then - assertThatThrownBy(() -> fontService.update(existMemberId, elseFont.getId(), updateDTO)) - .isExactlyInstanceOf(FontOwnerMismatchException.class); - } - @Test @DisplayName("font - getOrThrowById success test") void getOrThrowByIdSuccess() { @@ -217,6 +182,7 @@ void getFontsSuccess() { existMemberId, FontCreateDTO.builder() .name("폰트" + i) + .engName("ENG" + i) .example("예제" + i) .build(), fileDetails @@ -280,6 +246,7 @@ void deleteFontAccessDeniedFail() { // given FontCreateDTO createDTO = FontCreateDTO.builder() .name("다른사람폰트") + .engName("ENG1") .example("다른예제") .build(); @@ -299,6 +266,7 @@ void getFontPageSuccess() { existMemberId, FontCreateDTO.builder() .name("페이지폰트1") + .engName("ENG1") .example("예제1") .build(), fileDetails @@ -308,6 +276,7 @@ void getFontPageSuccess() { existMemberId, FontCreateDTO.builder() .name("페이지폰트2") + .engName("ENG2") .example("예제2") .build(), fileDetails @@ -317,6 +286,7 @@ void getFontPageSuccess() { existMemberId, FontCreateDTO.builder() .name("페이지폰트") + .engName("ENG3") .example("예제3") .build(), fileDetails @@ -378,6 +348,7 @@ void getMyPopularFontsSuccess() { existMemberId, FontCreateDTO.builder() .name("폰트1") + .engName("ENG1") .example("예1") .build(), fileDetails @@ -387,6 +358,7 @@ void getMyPopularFontsSuccess() { existMemberId, FontCreateDTO.builder() .name("폰트2") + .engName("ENG2") .example("예2") .build(), fileDetails @@ -396,6 +368,7 @@ void getMyPopularFontsSuccess() { existMemberId, FontCreateDTO.builder() .name("폰트3") + .engName("ENG3") .example("예3") .build(), fileDetails @@ -440,6 +413,7 @@ void getPopularFontsSuccess() { existMemberId, FontCreateDTO.builder() .name("폰트1") + .engName("ENG1") .example("예1") .build(), fileDetails @@ -449,6 +423,7 @@ void getPopularFontsSuccess() { existMemberId, FontCreateDTO.builder() .name("폰트2") + .engName("ENG2") .example("예2") .build(), fileDetails @@ -458,6 +433,7 @@ void getPopularFontsSuccess() { existMemberId, FontCreateDTO.builder() .name("폰트3") + .engName("ENG3") .example("예3") .build(), fileDetails @@ -503,6 +479,7 @@ void updateFontProgressSuccess() { // given FontCreateDTO dto = FontCreateDTO.builder() .name("진행중폰트") + .engName("ENG1") .example("예제입니다") .build(); diff --git a/src/test/java/org/fontory/fontorybe/integration/member/controller/MemberControllerIntegrationTest.java b/src/test/java/org/fontory/fontorybe/integration/member/controller/MemberControllerIntegrationTest.java index df709a5..8fcf209 100644 --- a/src/test/java/org/fontory/fontorybe/integration/member/controller/MemberControllerIntegrationTest.java +++ b/src/test/java/org/fontory/fontorybe/integration/member/controller/MemberControllerIntegrationTest.java @@ -47,9 +47,6 @@ void setUp() { UserPrincipal userPrincipal = new UserPrincipal(TEST_MEMBER_ID); validAccessToken = jwtTokenProvider.generateAccessToken(userPrincipal); testMember = memberLookupService.getOrThrowById(TEST_MEMBER_ID); - - given(cloudStorageService.getProfileImageUrl(testMember.getProfileImageKey())) - .willReturn(TEST_FILE_URL); } @Test @@ -60,8 +57,7 @@ void getInfoMemberSuccess() throws Exception { .andExpect(status().isOk()) .andExpect(content().contentType(MediaType.APPLICATION_JSON)) .andExpect(jsonPath("$.memberId").value(TEST_MEMBER_ID.intValue())) - .andExpect(jsonPath("$.nickname").value(TEST_MEMBER_NICKNAME)) - .andExpect(jsonPath("$.profileImageUrl").value(TEST_FILE_URL)); + .andExpect(jsonPath("$.nickname").value(TEST_MEMBER_NICKNAME)); } @Test diff --git a/src/test/java/org/fontory/fontorybe/integration/member/controller/ProfileControllerIntegrationTest.java b/src/test/java/org/fontory/fontorybe/integration/member/controller/ProfileControllerIntegrationTest.java index bb20fbc..4aaaa49 100644 --- a/src/test/java/org/fontory/fontorybe/integration/member/controller/ProfileControllerIntegrationTest.java +++ b/src/test/java/org/fontory/fontorybe/integration/member/controller/ProfileControllerIntegrationTest.java @@ -26,7 +26,7 @@ import java.util.UUID; import static org.fontory.fontorybe.TestConstants.*; -import static org.fontory.fontorybe.TestConstants.UPDATE_MEMBER_TERMS; +import static org.hamcrest.Matchers.containsString; import static org.hamcrest.Matchers.is; import static org.mockito.ArgumentMatchers.any; import static org.mockito.BDDMockito.given; @@ -62,8 +62,6 @@ void setUp() { .fileUploadTime(TEST_FILE_UPLOAD_TIME) .size(TEST_FILE_SIZE) .build(); - - given(fileService.uploadProfileImage(any(), any())).willReturn(mockFileUploadResult); } @Test @@ -79,34 +77,15 @@ void checkDuplicateFalseTest() throws Exception { @Test @DisplayName("PUT /member - update member success with valid Authorization JWT Cookie") void updateMemberSuccessTest() throws Exception { - MemberUpdateRequest memberUpdateRequest = new MemberUpdateRequest(UPDATE_MEMBER_NICKNAME, UPDATE_MEMBER_TERMS); + MemberUpdateRequest memberUpdateRequest = new MemberUpdateRequest(UPDATE_MEMBER_NICKNAME); String jsonRequest = objectMapper.writeValueAsString(memberUpdateRequest); - MockMultipartFile jsonPart = new MockMultipartFile( - "req", - null, - "application/json", - jsonRequest.getBytes(StandardCharsets.UTF_8) - ); - MockMultipartFile filePart = new MockMultipartFile( - "file", - UPDDATE_FILE_NAME, - "image/jpeg", - "fileBytes".getBytes(StandardCharsets.UTF_8) - ); - - MockMultipartHttpServletRequestBuilder builder = multipart("/member/me"); - builder.with(request -> { request.setMethod("PATCH"); return request; }); - - mockMvc.perform(builder - .file(jsonPart) - .file(filePart) + + mockMvc.perform(patch("/member/me") .cookie(new Cookie("accessToken", validAccessToken)) - .contentType(MediaType.MULTIPART_FORM_DATA)) + .contentType(MediaType.APPLICATION_JSON) + .content(jsonRequest)) .andExpect(status().isOk()) - .andExpect(jsonPath("$.memberId", is(TEST_MEMBER_ID.intValue()))) .andExpect(jsonPath("$.nickname", is(UPDATE_MEMBER_NICKNAME))) - .andExpect(jsonPath("$.terms", is(UPDATE_MEMBER_TERMS))) - .andExpect(jsonPath("$.profileImageUrl", is(testMember.getProfileImageKey()))) .andExpect(jsonPath("$.gender", is(testMember.getGender().name()))) .andExpect(jsonPath("$.birth", is(testMember.getBirth().toString()))); } @@ -114,7 +93,7 @@ void updateMemberSuccessTest() throws Exception { @Test @DisplayName("PUT /member without Authorization JWT Cookie returns 401") void putMemberWithoutAuthHeader() throws Exception { - MemberUpdateRequest memberUpdateRequest = new MemberUpdateRequest(UPDATE_MEMBER_NICKNAME, UPDATE_MEMBER_TERMS); + MemberUpdateRequest memberUpdateRequest = new MemberUpdateRequest(UPDATE_MEMBER_NICKNAME); String jsonRequest = objectMapper.writeValueAsString(memberUpdateRequest); mockMvc.perform(put("/member/me") diff --git a/src/test/java/org/fontory/fontorybe/integration/member/controller/RegistrationControllerIntegrationTest.java b/src/test/java/org/fontory/fontorybe/integration/member/controller/RegistrationControllerIntegrationTest.java index 79e4fa8..e1cce3f 100644 --- a/src/test/java/org/fontory/fontorybe/integration/member/controller/RegistrationControllerIntegrationTest.java +++ b/src/test/java/org/fontory/fontorybe/integration/member/controller/RegistrationControllerIntegrationTest.java @@ -31,8 +31,7 @@ import static org.fontory.fontorybe.TestConstants.*; import static org.mockito.ArgumentMatchers.any; import static org.mockito.BDDMockito.given; -import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get; -import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.multipart; +import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.*; import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.content; import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; @@ -58,12 +57,6 @@ void setUp() { UserPrincipal userPrincipal = new UserPrincipal(TEST_MEMBER_ID); validAccessToken = jwtTokenProvider.generateAccessToken(userPrincipal); - FileUploadResult mockFileUploadResult = FileUploadResult.builder() - .fileName(TEST_FILE_NAME) - .fileUrl(TEST_FILE_URL) - .fileUploadTime(TEST_FILE_UPLOAD_TIME) - .size(TEST_FILE_SIZE) - .build(); FileMetadata fileMetadata = FileMetadata.builder() .id(TEST_FILE_ID) .fileName(TEST_FILE_NAME) @@ -79,7 +72,6 @@ void setUp() { notInitializedAccessToken = jwtTokenProvider.generateAccessToken(UserPrincipal.from(notInitedMember)); given(fileService.getOrThrowById(any())).willReturn(fileMetadata); - given(fileService.uploadProfileImage(any(), any())).willReturn(mockFileUploadResult); } @Test @@ -105,27 +97,13 @@ void checkDuplicateTrueTest() throws Exception { @Test @DisplayName("POST /register - add member success with valid Authorization header") void addMemberSuccessTest() throws Exception { - InitMemberInfoRequest initMemberInfoRequest = new InitMemberInfoRequest(NEW_MEMBER_NICKNAME, NEW_MEMBER_GENDER, NEW_MEMBER_BIRTH, NEW_MEMBER_TERMS); + InitMemberInfoRequest initMemberInfoRequest = new InitMemberInfoRequest(NEW_MEMBER_NICKNAME, NEW_MEMBER_GENDER, NEW_MEMBER_BIRTH); String jsonRequest = objectMapper.writeValueAsString(initMemberInfoRequest); - MockMultipartFile jsonPart = new MockMultipartFile( - "req", - null, - "application/json", - jsonRequest.getBytes(StandardCharsets.UTF_8) - ); - MockMultipartFile filePart = new MockMultipartFile( - "file", - TEST_FILE_NAME, - "image/jpeg", - "fileBytes".getBytes(StandardCharsets.UTF_8) - ); - - - mockMvc.perform(multipart("/register") - .file(jsonPart) - .file(filePart) + + mockMvc.perform(post("/register") .cookie(new Cookie("accessToken", notInitializedAccessToken)) - .contentType(MediaType.MULTIPART_FORM_DATA)) + .contentType(MediaType.APPLICATION_JSON) + .content(jsonRequest)) .andExpect(status().isCreated()); } } diff --git a/src/test/java/org/fontory/fontorybe/integration/member/service/MemberUpdateServiceIntegrationTest.java b/src/test/java/org/fontory/fontorybe/integration/member/service/MemberUpdateServiceIntegrationTest.java index b0b7391..6c58ed6 100644 --- a/src/test/java/org/fontory/fontorybe/integration/member/service/MemberUpdateServiceIntegrationTest.java +++ b/src/test/java/org/fontory/fontorybe/integration/member/service/MemberUpdateServiceIntegrationTest.java @@ -72,7 +72,6 @@ void setUp() { .build(); given(fileService.getOrThrowById(any())).willReturn(profileImageFileMetadata); - given(fileService.uploadProfileImage(any(), any())).willReturn(profileImageFileUploadResult); } @Test @@ -85,8 +84,6 @@ void getOrThrowByIdTest() { () -> assertThat(foundMember.getNickname()).isEqualTo(TEST_MEMBER_NICKNAME), () -> assertThat(foundMember.getGender()).isEqualTo(TEST_MEMBER_GENDER), () -> assertThat(foundMember.getProvideId()).isEqualTo(TEST_PROVIDE_ID), - () -> assertThat(foundMember.getTerms()).isEqualTo(TEST_MEMBER_TERMS), - () -> assertThat(foundMember.getProfileImageKey()).isEqualTo(TEST_MEMBER_PROFILE_KEY), () -> assertThat(foundMember.getCreatedAt()).isNotNull(), () -> assertThat(foundMember.getUpdatedAt()).isNotNull(), () -> assertThat(foundMember.getDeletedAt()).isNull() @@ -104,7 +101,7 @@ void getOrThrowByIdTestX() { @Test @DisplayName("member - create success test") void createTest() { - InitMemberInfoRequest initNewMemberRequest = new InitMemberInfoRequest(NEW_MEMBER_NICKNAME, NEW_MEMBER_GENDER, NEW_MEMBER_BIRTH, NEW_MEMBER_TERMS); + InitMemberInfoRequest initNewMemberRequest = new InitMemberInfoRequest(NEW_MEMBER_NICKNAME, NEW_MEMBER_GENDER, NEW_MEMBER_BIRTH); ProvideCreateDto newProvideCreateDto = new ProvideCreateDto(NEW_MEMBER_PROVIDER, NEW_MEMBER_PROVIDED_ID, NEW_MEMBER_EMAIL); Provide createdProvide = provideService.create(newProvideCreateDto); Member createdMember = create(initNewMemberRequest, createdProvide); @@ -115,8 +112,6 @@ void createTest() { () -> assertThat(createdMember.getNickname()).isEqualTo(NEW_MEMBER_NICKNAME), () -> assertThat(createdMember.getGender()).isEqualTo(NEW_MEMBER_GENDER), () -> assertThat(createdMember.getBirth()).isEqualTo(NEW_MEMBER_BIRTH), - () -> assertThat(createdMember.getTerms()).isEqualTo(NEW_MEMBER_TERMS), - () -> assertThat(createdMember.getProfileImageKey()).isEqualTo(NEW_MEMBER_PROFILE_KEY), () -> assertThat(createdMember.getCreatedAt()).isNotNull(), () -> assertThat(createdMember.getUpdatedAt()).isNotNull() ); @@ -130,11 +125,11 @@ void createDuplicateNicknameTest() { Provide createdProvide1 = provideService.create(provideCreateDto1); Provide createdProvide2 = provideService.create(provideCreateDto2); // 첫 번째 회원 생성 - InitMemberInfoRequest initNewMemberRequest = new InitMemberInfoRequest(NEW_MEMBER_NICKNAME, NEW_MEMBER_GENDER, NEW_MEMBER_BIRTH, NEW_MEMBER_TERMS); + InitMemberInfoRequest initNewMemberRequest = new InitMemberInfoRequest(NEW_MEMBER_NICKNAME, NEW_MEMBER_GENDER, NEW_MEMBER_BIRTH); create(initNewMemberRequest, createdProvide1); // 동일 닉네임으로 또 회원 생성 시 예외 발생 - InitMemberInfoRequest duplicateInitNewMemberInfoRequest = new InitMemberInfoRequest(NEW_MEMBER_NICKNAME, NEW_MEMBER_GENDER, NEW_MEMBER_BIRTH, NEW_MEMBER_TERMS); + InitMemberInfoRequest duplicateInitNewMemberInfoRequest = new InitMemberInfoRequest(NEW_MEMBER_NICKNAME, NEW_MEMBER_GENDER, NEW_MEMBER_BIRTH); assertThatThrownBy( () -> create(duplicateInitNewMemberInfoRequest, createdProvide2)) .isExactlyInstanceOf(MemberDuplicateNameExistsException.class); @@ -145,7 +140,7 @@ void createDuplicateNicknameTest() { void updateTest() { // 기존에 존재하는 회원(TEST_MEMBER_ID) 조회 Member member = memberLookupService.getOrThrowById(TEST_MEMBER_ID); - MemberUpdateRequest memberUpdateRequest = new MemberUpdateRequest(UPDATE_MEMBER_NICKNAME, UPDATE_MEMBER_TERMS); + MemberUpdateRequest memberUpdateRequest = new MemberUpdateRequest(UPDATE_MEMBER_NICKNAME); // 업데이트 요청: 단일 회원 ID만 전달 Member updatedMember = memberUpdateService.update(TEST_MEMBER_ID, memberUpdateRequest); @@ -156,8 +151,6 @@ void updateTest() { () -> assertThat(updatedMember.getCreatedAt()).isEqualTo(member.getCreatedAt()), () -> assertThat(updatedMember.getProvideId()).isEqualTo(member.getProvideId()), () -> assertThat(updatedMember.getNickname()).isEqualTo(UPDATE_MEMBER_NICKNAME), - () -> assertThat(updatedMember.getProfileImageKey()).isEqualTo(member.getProfileImageKey()), - () -> assertThat(updatedMember.getTerms()).isEqualTo(UPDATE_MEMBER_TERMS), () -> assertThat(updatedMember.getUpdatedAt()).isAfter(member.getUpdatedAt()) ); } @@ -173,13 +166,13 @@ void updateDuplicateNicknameTest() { // 두 회원을 각각 생성 String uniqueNickname1 = UUID.randomUUID().toString(); String uniqueNickname2 = UUID.randomUUID().toString(); - InitMemberInfoRequest initNewMemberInfoRequestDto1 = new InitMemberInfoRequest(uniqueNickname1, NEW_MEMBER_GENDER, NEW_MEMBER_BIRTH, NEW_MEMBER_TERMS); - InitMemberInfoRequest initNewMemberInfoRequestDto2 = new InitMemberInfoRequest(uniqueNickname2, NEW_MEMBER_GENDER, NEW_MEMBER_BIRTH, NEW_MEMBER_TERMS); + InitMemberInfoRequest initNewMemberInfoRequestDto1 = new InitMemberInfoRequest(uniqueNickname1, NEW_MEMBER_GENDER, NEW_MEMBER_BIRTH); + InitMemberInfoRequest initNewMemberInfoRequestDto2 = new InitMemberInfoRequest(uniqueNickname2, NEW_MEMBER_GENDER, NEW_MEMBER_BIRTH); Member member1 = create(initNewMemberInfoRequestDto1, createdProvide1); create(initNewMemberInfoRequestDto2, createdProvide2); // member1의 닉네임을 이미 존재하는 이름(uniqueNickname2)으로 업데이트 시도하면 예외 발생 - MemberUpdateRequest memberUpdateRequest = new MemberUpdateRequest(uniqueNickname2, UPDATE_MEMBER_TERMS); + MemberUpdateRequest memberUpdateRequest = new MemberUpdateRequest(uniqueNickname2); Long member1Id = member1.getId(); assertThatThrownBy( @@ -190,7 +183,7 @@ void updateDuplicateNicknameTest() { @Test @DisplayName("member - update fail test caused by member not found") void updateNonExistentMemberTest() { - MemberUpdateRequest memberUpdateRequest = new MemberUpdateRequest(UPDATE_MEMBER_NICKNAME, UPDATE_MEMBER_TERMS); + MemberUpdateRequest memberUpdateRequest = new MemberUpdateRequest(UPDATE_MEMBER_NICKNAME); assertThatThrownBy( () -> memberUpdateService.update(nonExistentId, memberUpdateRequest)) .isExactlyInstanceOf(MemberNotFoundException.class); @@ -203,7 +196,7 @@ void disableTest() { ProvideCreateDto provideCreateDto = new ProvideCreateDto(Provider.GOOGLE, UUID.randomUUID().toString(), UUID.randomUUID().toString()); Provide createdProvide = provideService.create(provideCreateDto); - InitMemberInfoRequest initNewMemberRequest = new InitMemberInfoRequest(NEW_MEMBER_NICKNAME, NEW_MEMBER_GENDER, NEW_MEMBER_BIRTH, NEW_MEMBER_TERMS); + InitMemberInfoRequest initNewMemberRequest = new InitMemberInfoRequest(NEW_MEMBER_NICKNAME, NEW_MEMBER_GENDER, NEW_MEMBER_BIRTH); Member member = create(initNewMemberRequest, createdProvide); // 회원 비활성화 요청 (단일 ID) @@ -218,7 +211,7 @@ void disableAlreadyDisabledTest() { ProvideCreateDto provideCreateDto = new ProvideCreateDto(Provider.GOOGLE, UUID.randomUUID().toString(), UUID.randomUUID().toString()); Provide createdProvide = provideService.create(provideCreateDto); - InitMemberInfoRequest initNewMemberRequest = new InitMemberInfoRequest(NEW_MEMBER_NICKNAME, NEW_MEMBER_GENDER, NEW_MEMBER_BIRTH, NEW_MEMBER_TERMS); + InitMemberInfoRequest initNewMemberRequest = new InitMemberInfoRequest(NEW_MEMBER_NICKNAME, NEW_MEMBER_GENDER, NEW_MEMBER_BIRTH); Member member = create(initNewMemberRequest, createdProvide); // 최초 비활성화 처리 @@ -233,14 +226,6 @@ void disableAlreadyDisabledTest() { private Member create(InitMemberInfoRequest initNewMemberInfoRequest, Provide provide) { Member defaultMember = memberCreationService.createDefaultMember(provide); - MockMultipartFile file = new MockMultipartFile( - TEST_FILE_NAME, // RequestPart 이름 - TEST_FILE_NAME, // 원본 파일명 - "image/png", // Content-Type - "dummy-image-data".getBytes() // 파일 내용 - ); - FileUploadResult fileUploadResult = fileService.uploadProfileImage(file, defaultMember.getId()); - System.out.println("fileUploadResult = " + fileUploadResult); - return memberOnboardService.initNewMemberInfo(defaultMember.getId(), initNewMemberInfoRequest, fileUploadResult); + return memberOnboardService.initNewMemberInfo(defaultMember.getId(), initNewMemberInfoRequest); } } \ No newline at end of file diff --git a/src/test/java/org/fontory/fontorybe/unit/file/FileRequestMapperTest.java b/src/test/java/org/fontory/fontorybe/unit/file/FileRequestMapperTest.java index da1a3e3..6868b60 100644 --- a/src/test/java/org/fontory/fontorybe/unit/file/FileRequestMapperTest.java +++ b/src/test/java/org/fontory/fontorybe/unit/file/FileRequestMapperTest.java @@ -108,8 +108,7 @@ private static InitMemberInfoRequest createMemberRequest(String nickname) { return new InitMemberInfoRequest( nickname, Gender.MALE, - LocalDate.of(2025, 1, 26), - true + LocalDate.of(2025, 1, 26) ); } diff --git a/src/test/java/org/fontory/fontorybe/unit/file/FileServiceTest.java b/src/test/java/org/fontory/fontorybe/unit/file/FileServiceTest.java index c9057cc..e6b84ad 100644 --- a/src/test/java/org/fontory/fontorybe/unit/file/FileServiceTest.java +++ b/src/test/java/org/fontory/fontorybe/unit/file/FileServiceTest.java @@ -71,8 +71,7 @@ private static InitMemberInfoRequest createMemberRequest(String nickname) { return new InitMemberInfoRequest( nickname, Gender.MALE, - LocalDate.of(2025, 1, 26), - true + LocalDate.of(2025, 1, 26) ); } @@ -84,7 +83,7 @@ void getOrThrowByIdTest() { MultipartFile mockFile = createValidImageFile(profileImageFilename, "image/jpeg"); // Upload a file to get its ID - FileUploadResult uploadResult = fileService.uploadProfileImage(mockFile, existMemberId); + FileUploadResult uploadResult = fileService.uploadFontTemplateImage(mockFile, existMemberId); FileMetadata savedMetadata = testContainer.fileRepository.findById(uploadResult.getId()).get(); Long fileId = savedMetadata.getId(); @@ -96,7 +95,7 @@ void getOrThrowByIdTest() { () -> assertThat(retrievedMetadata).isNotNull(), () -> assertThat(retrievedMetadata.getId()).isEqualTo(fileId), () -> assertThat(retrievedMetadata.getFileName()).isEqualTo(existMemberId + ".jpg"), - () -> assertThat(retrievedMetadata.getFileType()).isEqualTo(FileType.PROFILE_IMAGE), + () -> assertThat(retrievedMetadata.getFileType()).isEqualTo(FileType.FONT_PAPER), () -> assertThat(retrievedMetadata.getUploaderId()).isEqualTo(existMemberId), () -> assertThat(retrievedMetadata.getSize()).isEqualTo(fileContent.length), () -> assertThat(retrievedMetadata.getUploadedAt()).isNotNull(), @@ -117,41 +116,6 @@ void getOrThrowByIdNonExistentTest() { ).isExactlyInstanceOf(FileNotFoundException.class); } - @Test - @DisplayName("uploadProfileImage - should upload profile image successfully") - void uploadProfileImageTest() { - // given - MultipartFile mockFile = createValidImageFile(profileImageFilename, "image/jpeg"); - - // when - FileUploadResult result = fileService.uploadProfileImage(mockFile, existMemberId); - - // then - assertAll( - () -> assertThat(result).isNotNull(), - () -> assertThat(result.getFileName()).isEqualTo(existMemberId + ".jpg"), - () -> assertThat(result.getFileUrl()).isNotNull(), - () -> assertThat(result.getFileUploadTime()).isNotNull(), - () -> assertThat(result.getSize()).isEqualTo(fileContent.length) - ); - - // 멤버의 프로필 이미지가 업데이트되었는지 확인 - Member updatedMember = memberLookupService.getOrThrowById(existMemberId); - assertThat(updatedMember.getProfileImageKey()).isNotNull(); - } - - @Test - @DisplayName("uploadProfileImage - should throw exception when member doesn't exist") - void uploadProfileImageNonExistentMemberTest() { - // given - MultipartFile mockFile = createValidImageFile(profileImageFilename, "image/jpeg"); - - // when & then - assertThatThrownBy( - () -> fileService.uploadProfileImage(mockFile, nonExistentId) - ).isExactlyInstanceOf(MemberNotFoundException.class); - } - @Test @DisplayName("uploadFontTemplateImage - should upload font template image successfully") void uploadFontTemplateImageTest() { @@ -187,10 +151,10 @@ void uploadFontTemplateImageNonExistentMemberTest() { @DisplayName("upload and retrieve file metadata should work together") void uploadAndRetrieveTest() { // given - MockMultipartFile mockFile = createValidImageFile("profile.jpg", "image/jpeg"); + MockMultipartFile mockFile = createValidImageFile("fontPaper.jpg", "image/jpeg"); // when - upload file - FileUploadResult uploadResult = fileService.uploadProfileImage(mockFile, existMemberId); + FileUploadResult uploadResult = fileService.uploadFontTemplateImage(mockFile, existMemberId); // Find the file ID from repository FileMetadata savedMetadata = testContainer.fileRepository.findById(uploadResult.getId()).get(); @@ -204,7 +168,7 @@ void uploadAndRetrieveTest() { () -> assertThat(retrievedMetadata).isNotNull(), () -> assertThat(retrievedMetadata.getId()).isEqualTo(fileId), () -> assertThat(retrievedMetadata.getFileName()).isEqualTo(existMemberId + ".jpg"), - () -> assertThat(retrievedMetadata.getFileType()).isEqualTo(FileType.PROFILE_IMAGE), + () -> assertThat(retrievedMetadata.getFileType()).isEqualTo(FileType.FONT_PAPER), () -> assertThat(uploadResult.getFileUrl()).contains(retrievedMetadata.getKey()) ); } @@ -213,24 +177,20 @@ void uploadAndRetrieveTest() { @DisplayName("uploading different types of images should update FileMetadata correctly") void uploadDifferentImagesTest() { // given - MockMultipartFile profileFile = createValidImageFile("profile.jpg", "image/jpeg"); - MockMultipartFile templateFile = createValidImageFile("template.png", "image/png"); + MockMultipartFile jpgFile = createValidImageFile("profile.jpg", "image/jpeg"); + MockMultipartFile pngFile = createValidImageFile("template.png", "image/png"); // when - upload profile image - FileUploadResult profileResult = fileService.uploadProfileImage(profileFile, existMemberId); + FileUploadResult jpgResult = fileService.uploadFontTemplateImage(jpgFile, existMemberId); // when - upload template image - FileUploadResult templateResult = fileService.uploadFontTemplateImage(templateFile, existMemberId); + FileUploadResult pngResult = fileService.uploadFontTemplateImage(pngFile, existMemberId); // then assertAll( - () -> assertThat(profileResult.getFileName()).contains("jpg"), - () -> assertThat(templateResult.getFileName()).contains("png"), - () -> assertThat(((FakeFileRepository)testContainer.fileRepository).findAll()).hasSize(3) + () -> assertThat(jpgResult.getFileName()).contains("jpg"), + () -> assertThat(pngResult.getFileName()).contains("png"), + () -> assertThat(((FakeFileRepository)testContainer.fileRepository).findAll()).hasSize(2) ); - - // Member should have profile image updated - Member updatedMember = memberLookupService.getOrThrowById(existMemberId); - assertThat(updatedMember.getProfileImageKey()).isNotNull(); } } \ No newline at end of file diff --git a/src/test/java/org/fontory/fontorybe/unit/member/controller/MemberControllerTest.java b/src/test/java/org/fontory/fontorybe/unit/member/controller/MemberControllerTest.java index 41a2653..8da1d3f 100644 --- a/src/test/java/org/fontory/fontorybe/unit/member/controller/MemberControllerTest.java +++ b/src/test/java/org/fontory/fontorybe/unit/member/controller/MemberControllerTest.java @@ -69,7 +69,6 @@ void getInfoMemberSuccessTest() { assertAll( () -> assertThat(body.getMemberId()).isEqualTo(testMember.getId()), - () -> assertThat(body.getProfileImageUrl()).isEqualTo(cloudStorageService.getProfileImageUrl(testMember.getProfileImageKey())), () -> assertThat(body.getNickname()).isEqualTo(testMember.getNickname()) ); } diff --git a/src/test/java/org/fontory/fontorybe/unit/member/controller/ProfileControllerTest.java b/src/test/java/org/fontory/fontorybe/unit/member/controller/ProfileControllerTest.java index 0871ca4..74f50e1 100644 --- a/src/test/java/org/fontory/fontorybe/unit/member/controller/ProfileControllerTest.java +++ b/src/test/java/org/fontory/fontorybe/unit/member/controller/ProfileControllerTest.java @@ -31,7 +31,6 @@ import static org.assertj.core.api.Assertions.assertThat; import static org.assertj.core.api.Assertions.assertThatThrownBy; import static org.fontory.fontorybe.TestConstants.*; -import static org.fontory.fontorybe.TestConstants.UPDATE_MEMBER_TERMS; import static org.junit.jupiter.api.Assertions.assertAll; class ProfileControllerTest { @@ -111,21 +110,18 @@ void disableAlreadyDisabledMemberTest() { void testUpdateMember() { //given MemberUpdateRequest memberUpdateRequest = new MemberUpdateRequest( - UPDATE_MEMBER_NICKNAME, - UPDATE_MEMBER_TERMS + UPDATE_MEMBER_NICKNAME ); //when - ResponseEntity response = profileController.updateMember(testMemberUserPrincipal, memberUpdateRequest, mockFiles); + ResponseEntity response = profileController.updateMember(testMemberUserPrincipal, memberUpdateRequest); MyProfileResponse body = response.getBody(); //then assertAll( () -> assertThat(response.getStatusCode()).isEqualTo(HttpStatus.OK), () -> assertThat(body).isNotNull(), - () -> assertThat(body.getNickname()).isEqualTo(UPDATE_MEMBER_NICKNAME), - () -> assertThat(body.getTerms()).isEqualTo(UPDATE_MEMBER_TERMS), - () -> assertThat(body.getProfileImageUrl()).isEqualTo(cloudStorageService.getProfileImageUrl(testMember.getProfileImageKey())) + () -> assertThat(body.getNickname()).isEqualTo(UPDATE_MEMBER_NICKNAME) ); } @@ -134,10 +130,10 @@ void testUpdateMember() { void updateMemberNonExistentTest() { // given UserPrincipal nonExistentUserPrincipal = new UserPrincipal(NON_EXIST_ID); - MemberUpdateRequest memberUpdateRequest = new MemberUpdateRequest(TestConstants.UPDATE_MEMBER_NICKNAME, UPDATE_MEMBER_TERMS); + MemberUpdateRequest memberUpdateRequest = new MemberUpdateRequest(TestConstants.UPDATE_MEMBER_NICKNAME); // when & then - assertThatThrownBy(() -> profileController.updateMember(nonExistentUserPrincipal, memberUpdateRequest, mockFiles)) + assertThatThrownBy(() -> profileController.updateMember(nonExistentUserPrincipal, memberUpdateRequest)) .isInstanceOf(MemberNotFoundException.class); } } diff --git a/src/test/java/org/fontory/fontorybe/unit/member/controller/RegistrationControllerTest.java b/src/test/java/org/fontory/fontorybe/unit/member/controller/RegistrationControllerTest.java index dc17926..c29a4e4 100644 --- a/src/test/java/org/fontory/fontorybe/unit/member/controller/RegistrationControllerTest.java +++ b/src/test/java/org/fontory/fontorybe/unit/member/controller/RegistrationControllerTest.java @@ -73,17 +73,10 @@ void testCheckDuplicateFalse() { @DisplayName("addMember returns created member response") void testAddMember() { //given - MockMultipartFile file = new MockMultipartFile( - "file", // RequestPart 이름 - "test.png", // 원본 파일명 - "image/png", // Content-Type - "dummy-image-data".getBytes() // 파일 내용 - ); - List files = Collections.singletonList(file); Member notInitedMember = testContainer.createNotInitedMember(); //when - ResponseEntity response = registrationController.register(UserPrincipal.from(notInitedMember), newInitMemberInfoRequest, files); + ResponseEntity response = registrationController.register(UserPrincipal.from(notInitedMember), newInitMemberInfoRequest); MemberCreateResponse body = response.getBody(); //then diff --git a/src/test/java/org/fontory/fontorybe/unit/member/service/MemberUpdateServiceTest.java b/src/test/java/org/fontory/fontorybe/unit/member/service/MemberUpdateServiceTest.java index f119132..af1efd2 100644 --- a/src/test/java/org/fontory/fontorybe/unit/member/service/MemberUpdateServiceTest.java +++ b/src/test/java/org/fontory/fontorybe/unit/member/service/MemberUpdateServiceTest.java @@ -71,8 +71,6 @@ void getOrThrownByIdTest() { () -> assertThat(foundMember.getNickname()).isEqualTo(TEST_MEMBER_NICKNAME), () -> assertThat(foundMember.getGender()).isEqualTo(TEST_MEMBER_GENDER), () -> assertThat(foundMember.getProvideId()).isEqualTo(testMemberProvideId), - () -> assertThat(foundMember.getTerms()).isEqualTo(TEST_MEMBER_TERMS), - () -> assertThat(foundMember.getProfileImageKey()).isNotEqualTo(DEFAULT_PROFILE_KEY), () -> assertThat(foundMember.getCreatedAt()).isNotNull(), () -> assertThat(foundMember.getUpdatedAt()).isNotNull(), () -> assertThat(foundMember.getDeletedAt()).isNull() @@ -102,7 +100,6 @@ void makeDefaultMember() { () -> assertThat(defaultMember.getNickname()).isNotNull(), () -> assertThat(defaultMember.getGender()).isEqualTo(memberDefaults.getGender()), () -> assertThat(defaultMember.getBirth()).isEqualTo(memberDefaults.getBirth()), - () -> assertThat(defaultMember.getProfileImageKey()).isEqualTo(memberDefaults.getProfileImageKey()), () -> assertThat(defaultMember.getCreatedAt()).isNotNull(), () -> assertThat(defaultMember.getUpdatedAt()).isNotNull() ); @@ -114,7 +111,7 @@ void createTest() { ProvideCreateDto provideCreateDto = new ProvideCreateDto(NEW_MEMBER_PROVIDER, NEW_MEMBER_PROVIDED_ID, NEW_MEMBER_EMAIL); Provide createdProvide = testContainer.provideService.create(provideCreateDto); - InitMemberInfoRequest initNewMemberRequestDto = new InitMemberInfoRequest(NEW_MEMBER_NICKNAME, NEW_MEMBER_GENDER, NEW_MEMBER_BIRTH, NEW_MEMBER_TERMS); + InitMemberInfoRequest initNewMemberRequestDto = new InitMemberInfoRequest(NEW_MEMBER_NICKNAME, NEW_MEMBER_GENDER, NEW_MEMBER_BIRTH); Member createdMember = testContainer.create(initNewMemberRequestDto, createdProvide); assertAll( @@ -123,8 +120,6 @@ void createTest() { () -> assertThat(createdMember.getNickname()).isEqualTo(NEW_MEMBER_NICKNAME), () -> assertThat(createdMember.getGender()).isEqualTo(NEW_MEMBER_GENDER), () -> assertThat(createdMember.getBirth()).isEqualTo(NEW_MEMBER_BIRTH), - () -> assertThat(createdMember.getTerms()).isEqualTo(NEW_MEMBER_TERMS), - () -> assertThat(createdMember.getProfileImageKey()).isNotEqualTo(DEFAULT_PROFILE_KEY), () -> assertThat(createdMember.getCreatedAt()).isNotNull(), () -> assertThat(createdMember.getUpdatedAt()).isNotNull() ); @@ -139,11 +134,11 @@ void createDuplicateNicknameTest() { Provide createdProvide1 = testContainer.provideService.create(provideCreateDto1); Provide createdProvide2 = testContainer.provideService.create(provideCreateDto2); - InitMemberInfoRequest initNewMemberRequestDto = new InitMemberInfoRequest(NEW_MEMBER_NICKNAME, NEW_MEMBER_GENDER, NEW_MEMBER_BIRTH, NEW_MEMBER_TERMS); + InitMemberInfoRequest initNewMemberRequestDto = new InitMemberInfoRequest(NEW_MEMBER_NICKNAME, NEW_MEMBER_GENDER, NEW_MEMBER_BIRTH); testContainer.create(initNewMemberRequestDto, createdProvide1); // 동일 닉네임으로 또 회원 생성 시 예외 발생 - InitMemberInfoRequest duplicateInitNewMemberInfoRequest = new InitMemberInfoRequest(NEW_MEMBER_NICKNAME, NEW_MEMBER_GENDER, NEW_MEMBER_BIRTH, NEW_MEMBER_TERMS); + InitMemberInfoRequest duplicateInitNewMemberInfoRequest = new InitMemberInfoRequest(NEW_MEMBER_NICKNAME, NEW_MEMBER_GENDER, NEW_MEMBER_BIRTH); assertThatThrownBy( () -> testContainer.create(duplicateInitNewMemberInfoRequest, createdProvide2)) .isExactlyInstanceOf(MemberDuplicateNameExistsException.class); @@ -154,7 +149,7 @@ void createDuplicateNicknameTest() { void updateTest() { Long requestMemberId = testMemberId; Member member = memberLookupService.getOrThrowById(testMemberId); - MemberUpdateRequest memberUpdateRequest = new MemberUpdateRequest(UPDATE_MEMBER_NICKNAME, UPDATE_MEMBER_TERMS); + MemberUpdateRequest memberUpdateRequest = new MemberUpdateRequest(UPDATE_MEMBER_NICKNAME); Member updatedMember = memberUpdateService.update(requestMemberId, memberUpdateRequest); assertAll( @@ -164,8 +159,6 @@ void updateTest() { () -> assertThat(updatedMember.getCreatedAt()).isEqualTo(member.getCreatedAt()), () -> assertThat(updatedMember.getProvideId()).isEqualTo(member.getProvideId()), () -> assertThat(updatedMember.getNickname()).isEqualTo(UPDATE_MEMBER_NICKNAME), - () -> assertThat(updatedMember.getProfileImageKey()).isEqualTo(member.getProfileImageKey()), - () -> assertThat(updatedMember.getTerms()).isEqualTo(UPDATE_MEMBER_TERMS), () -> assertThat(updatedMember.getUpdatedAt()).isAfter(member.getUpdatedAt()) ); } @@ -181,13 +174,13 @@ void updateDuplicateNicknameTest() { String uniqueNickname1 = UUID.randomUUID().toString(); String uniqueNickname2 = UUID.randomUUID().toString(); - InitMemberInfoRequest initNewMemberRequestDto1 = new InitMemberInfoRequest(uniqueNickname1, Gender.MALE, NEW_MEMBER_BIRTH, TEST_MEMBER_TERMS); - InitMemberInfoRequest initNewMemberRequestDto2 = new InitMemberInfoRequest(uniqueNickname2, Gender.FEMALE, NEW_MEMBER_BIRTH, TEST_MEMBER_TERMS); + InitMemberInfoRequest initNewMemberRequestDto1 = new InitMemberInfoRequest(uniqueNickname1, Gender.MALE, NEW_MEMBER_BIRTH); + InitMemberInfoRequest initNewMemberRequestDto2 = new InitMemberInfoRequest(uniqueNickname2, Gender.FEMALE, NEW_MEMBER_BIRTH); Member member1 = testContainer.create(initNewMemberRequestDto1, createdProvide1); testContainer.create(initNewMemberRequestDto2, createdProvide2); // member1의 닉네임을 이미 존재하는 이름으로 업데이트 시도하면 예외 발생 - MemberUpdateRequest memberUpdateRequest = new MemberUpdateRequest(uniqueNickname2, UPDATE_MEMBER_TERMS); + MemberUpdateRequest memberUpdateRequest = new MemberUpdateRequest(uniqueNickname2); assertThatThrownBy( () -> memberUpdateService.update(member1.getId(), memberUpdateRequest)) .isExactlyInstanceOf(MemberDuplicateNameExistsException.class); @@ -201,8 +194,8 @@ void createProvideMemberMoreThanOneTest() { String uniqueNickname1 = UUID.randomUUID().toString(); String uniqueNickname2 = UUID.randomUUID().toString(); - InitMemberInfoRequest initNewMemberRequestDto1 = new InitMemberInfoRequest(uniqueNickname1, Gender.MALE, NEW_MEMBER_BIRTH, TEST_MEMBER_TERMS); - InitMemberInfoRequest initNewMemberRequestDto2 = new InitMemberInfoRequest(uniqueNickname2, Gender.MALE, NEW_MEMBER_BIRTH, TEST_MEMBER_TERMS); + InitMemberInfoRequest initNewMemberRequestDto1 = new InitMemberInfoRequest(uniqueNickname1, Gender.MALE, NEW_MEMBER_BIRTH); + InitMemberInfoRequest initNewMemberRequestDto2 = new InitMemberInfoRequest(uniqueNickname2, Gender.MALE, NEW_MEMBER_BIRTH); testContainer.create(initNewMemberRequestDto1, createdProvide); assertThatThrownBy( @@ -214,7 +207,7 @@ void createProvideMemberMoreThanOneTest() { @DisplayName("member - update fail test caused by member not found") void updateNonExistentMemberTest() { // 존재하지 않는 회원(-1L)을 대상으로 업데이트 시도 시 예외 발생 - MemberUpdateRequest memberUpdateRequest = new MemberUpdateRequest(UPDATE_MEMBER_NICKNAME, UPDATE_MEMBER_TERMS); + MemberUpdateRequest memberUpdateRequest = new MemberUpdateRequest(UPDATE_MEMBER_NICKNAME); assertThatThrownBy( () -> memberUpdateService.update(nonExistentId, memberUpdateRequest)) .isExactlyInstanceOf(MemberNotFoundException.class); @@ -226,15 +219,13 @@ void updateNoNicknameChangeTest() { // 닉네임 변경 없이 다른 정보만 업데이트하는 경우 Member member = memberLookupService.getOrThrowById(testMemberId); // 업데이트 DTO에서 기존 닉네임 그대로 사용 - MemberUpdateRequest memberUpdateRequest = new MemberUpdateRequest(member.getNickname(), UPDATE_MEMBER_TERMS); + MemberUpdateRequest memberUpdateRequest = new MemberUpdateRequest(member.getNickname()); // 같은 닉네임을 사용하더라도 본인의 정보이므로 중복 체크가 통과되어 업데이트 성공해야 함 Member updatedMember = memberUpdateService.update(member.getId(), memberUpdateRequest); assertAll( () -> assertThat(updatedMember.getId()).isEqualTo(member.getId()), - () -> assertThat(updatedMember.getNickname()).isEqualTo(member.getNickname()), - () -> assertThat(updatedMember.getProfileImageKey()).isEqualTo(member.getProfileImageKey()), - () -> assertThat(updatedMember.getTerms()).isEqualTo(UPDATE_MEMBER_TERMS) + () -> assertThat(updatedMember.getNickname()).isEqualTo(member.getNickname()) ); } @@ -254,7 +245,7 @@ void disableTest() { ProvideCreateDto provideCreateDto = new ProvideCreateDto(NEW_MEMBER_PROVIDER, NEW_MEMBER_PROVIDED_ID, NEW_MEMBER_EMAIL); Provide createdProvide = testContainer.provideService.create(provideCreateDto); - InitMemberInfoRequest initNewMemberRequestDto = new InitMemberInfoRequest(NEW_MEMBER_NICKNAME, NEW_MEMBER_GENDER, NEW_MEMBER_BIRTH, NEW_MEMBER_TERMS); + InitMemberInfoRequest initNewMemberRequestDto = new InitMemberInfoRequest(NEW_MEMBER_NICKNAME, NEW_MEMBER_GENDER, NEW_MEMBER_BIRTH); Member member = testContainer.create(initNewMemberRequestDto, createdProvide); // 회원 비활성화 @@ -272,7 +263,7 @@ void disableAlreadyDisabledTest() { ProvideCreateDto provideCreateDto = new ProvideCreateDto(NEW_MEMBER_PROVIDER, NEW_MEMBER_PROVIDED_ID, NEW_MEMBER_EMAIL); Provide createdProvide = testContainer.provideService.create(provideCreateDto); - InitMemberInfoRequest initNewMemberRequestDto = new InitMemberInfoRequest(NEW_MEMBER_NICKNAME, NEW_MEMBER_GENDER, NEW_MEMBER_BIRTH, NEW_MEMBER_TERMS); + InitMemberInfoRequest initNewMemberRequestDto = new InitMemberInfoRequest(NEW_MEMBER_NICKNAME, NEW_MEMBER_GENDER, NEW_MEMBER_BIRTH); Member member = testContainer.create(initNewMemberRequestDto, createdProvide); // 회원 비활성화 diff --git a/src/test/java/org/fontory/fontorybe/unit/mock/FakeCloudStorageService.java b/src/test/java/org/fontory/fontorybe/unit/mock/FakeCloudStorageService.java index 896c90d..0c0faae 100644 --- a/src/test/java/org/fontory/fontorybe/unit/mock/FakeCloudStorageService.java +++ b/src/test/java/org/fontory/fontorybe/unit/mock/FakeCloudStorageService.java @@ -18,17 +18,6 @@ public FakeCloudStorageService(S3Config s3Config) { this.s3Config = s3Config; } - @Override - public FileMetadata uploadProfileImage(FileCreate fileCreate, String key) { - AmazonS3PutRequest amazonS3PutRequest = AmazonS3PutRequest.from( - fileCreate, - key, - s3Config.getBucketName(FileType.PROFILE_IMAGE), - s3Config.getPrefix(FileType.PROFILE_IMAGE), - LocalDateTime.now()); - return uploadFile(amazonS3PutRequest).toModel(); - } - @Override public FileMetadata uploadFontTemplateImage(FileCreate request) { String key = UUID.randomUUID().toString(); @@ -45,11 +34,6 @@ private String getFileUrl(FileType fileType, String key) { return String.format("%s/%s/%s", s3Config.getCdnUrl(), s3Config.getPrefix(fileType), key); } - @Override - public String getProfileImageUrl(String key) { - return getFileUrl(FileType.PROFILE_IMAGE, key); - } - @Override public String getFontPaperUrl(String key) { return getFileUrl(FileType.FONT_PAPER, key); diff --git a/src/test/java/org/fontory/fontorybe/unit/mock/FakeMemberRepository.java b/src/test/java/org/fontory/fontorybe/unit/mock/FakeMemberRepository.java index 49fec4f..145c273 100644 --- a/src/test/java/org/fontory/fontorybe/unit/mock/FakeMemberRepository.java +++ b/src/test/java/org/fontory/fontorybe/unit/mock/FakeMemberRepository.java @@ -23,8 +23,6 @@ public Member save(Member member) { .nickname(member.getNickname()) .gender(member.getGender()) .birth(member.getBirth()) - .terms(member.getTerms()) - .profileImageKey(member.getProfileImageKey()) .provideId(member.getProvideId()) .status(member.getStatus()) .createdAt(now) @@ -39,8 +37,6 @@ public Member save(Member member) { .nickname(member.getNickname()) .gender(member.getGender()) .birth(member.getBirth()) - .terms(member.getTerms()) - .profileImageKey(member.getProfileImageKey()) .provideId(member.getProvideId()) .status(member.getStatus()) .createdAt(member.getCreatedAt()) diff --git a/src/test/java/org/fontory/fontorybe/unit/mock/TestContainer.java b/src/test/java/org/fontory/fontorybe/unit/mock/TestContainer.java index 064f1a8..7802c19 100644 --- a/src/test/java/org/fontory/fontorybe/unit/mock/TestContainer.java +++ b/src/test/java/org/fontory/fontorybe/unit/mock/TestContainer.java @@ -15,7 +15,6 @@ import org.fontory.fontorybe.file.application.port.CloudStorageService; import org.fontory.fontorybe.file.application.port.FileRepository; import org.fontory.fontorybe.file.application.port.FileService; -import org.fontory.fontorybe.file.domain.FileUploadResult; import org.fontory.fontorybe.member.controller.MemberController; import org.fontory.fontorybe.member.controller.ProfileController; import org.fontory.fontorybe.member.controller.RegistrationController; @@ -38,7 +37,6 @@ import org.fontory.fontorybe.provide.service.port.ProvideRepository; import org.springframework.context.ApplicationEventPublisher; import org.springframework.mock.web.MockMultipartFile; -import org.springframework.web.multipart.MultipartFile; import javax.crypto.KeyGenerator; import javax.crypto.SecretKey; @@ -138,14 +136,11 @@ public TestContainer() { .build(); memberDefaults = new MemberDefaults( - LocalDate.of(1999, 12, 31), - false, - DEFAULT_PROFILE_KEY); + LocalDate.of(1999, 12, 31)); fileService = FileServiceImpl.builder() .memberLookupService(memberLookupService) .memberDefaults(memberDefaults) - .memberUpdateService(memberUpdateService) .fileRepository(fileRepository) .fileRequestMapper(fileRequestMapper) .eventPublisher(eventPublisher) @@ -191,6 +186,7 @@ public TestContainer() { registrationController = RegistrationController.builder() .memberLookupService(memberLookupService) .memberOnboardService(memberOnboardService) + .cloudStorageService(cloudStorageService) .fileService(fileService) .build(); } @@ -222,15 +218,14 @@ public Member create(InitMemberInfoRequest initNewMemberInfoRequest, Provide pro "image/png", // Content-Type "dummy-image-data".getBytes() // 파일 내용 ); - FileUploadResult fileUploadResult = fileService.uploadProfileImage(file, defaultMember.getId()); - return memberOnboardService.initNewMemberInfo(defaultMember.getId(), initNewMemberInfoRequest, fileUploadResult); + return memberOnboardService.initNewMemberInfo(defaultMember.getId(), initNewMemberInfoRequest); } public final ProvideCreateDto testMemberProvideCreateDto = new ProvideCreateDto(TEST_MEMBER_PROVIDER, TEST_MEMBER_PROVIDED_ID, TEST_MEMBER_EMAIL); public Provide testMemberProvide; public Provide newMemberProvide; - public final InitMemberInfoRequest newInitMemberInfoRequest = new InitMemberInfoRequest(NEW_MEMBER_NICKNAME, NEW_MEMBER_GENDER, NEW_MEMBER_BIRTH, NEW_MEMBER_TERMS); + public final InitMemberInfoRequest newInitMemberInfoRequest = new InitMemberInfoRequest(NEW_MEMBER_NICKNAME, NEW_MEMBER_GENDER, NEW_MEMBER_BIRTH); public final ProvideCreateDto newMemberProvideCreateDto = new ProvideCreateDto(NEW_MEMBER_PROVIDER, NEW_MEMBER_PROVIDED_ID, NEW_MEMBER_EMAIL); public Member createNotInitedMember() { @@ -240,13 +235,13 @@ public Member createNotInitedMember() { public Member createTestMember() { testMemberProvide = provideService.create(testMemberProvideCreateDto); - InitMemberInfoRequest initMemberInfoRequest = new InitMemberInfoRequest(TEST_MEMBER_NICKNAME, TEST_MEMBER_GENDER, TEST_MEMBER_BIRTH, TEST_MEMBER_TERMS); + InitMemberInfoRequest initMemberInfoRequest = new InitMemberInfoRequest(TEST_MEMBER_NICKNAME, TEST_MEMBER_GENDER, TEST_MEMBER_BIRTH); return create(initMemberInfoRequest, testMemberProvide); } public Member createNewMember() { newMemberProvide = provideService.create(newMemberProvideCreateDto); - InitMemberInfoRequest initNewMemberInfoRequest = new InitMemberInfoRequest(NEW_MEMBER_NICKNAME, NEW_MEMBER_GENDER, NEW_MEMBER_BIRTH, NEW_MEMBER_TERMS); + InitMemberInfoRequest initNewMemberInfoRequest = new InitMemberInfoRequest(NEW_MEMBER_NICKNAME, NEW_MEMBER_GENDER, NEW_MEMBER_BIRTH); return create(initNewMemberInfoRequest, newMemberProvide); } } diff --git a/src/test/resources/sql/createFileTestData.sql b/src/test/resources/sql/createFileTestData.sql index 2f048e6..96e61b3 100644 --- a/src/test/resources/sql/createFileTestData.sql +++ b/src/test/resources/sql/createFileTestData.sql @@ -3,8 +3,8 @@ truncate table `member`; truncate table `provide`; -- Test member data -insert into `member` (`member_id`, `nickname`, `gender`, `birth`, `terms`, `profile_image_key`, `provide_id`, `status`,`created_at`, `updated_at`) -values (999, 'existMemberNickName', 'MALE', '2025-01-26', 1, 'existMemberProfileImage', 999, 'ACTIVATE', NOW(), NOW()); +insert into `member` (`member_id`, `nickname`, `gender`, `birth`, `provide_id`, `status`,`created_at`, `updated_at`) +values (999, 'existMemberNickName', 'MALE', '2025-01-26', 999, 'ACTIVATE', NOW(), NOW()); -- Test provide data insert into `provide` (`provide_id`, `provider`, `provided_id`, `email`, `member_id`) diff --git a/src/test/resources/sql/createFontTestData.sql b/src/test/resources/sql/createFontTestData.sql index 58d0018..8b055fa 100644 --- a/src/test/resources/sql/createFontTestData.sql +++ b/src/test/resources/sql/createFontTestData.sql @@ -26,11 +26,11 @@ INSERT INTO `font` ( '2025-04-08 10:00:00' ); -insert into `member` (`member_id`, `nickname`, `gender`, `birth`, `terms`, `profile_image_key`, `provide_id`, `status`, `created_at`, `updated_at`) -values (999, 'existMemberNickName', 'MALE', '2025-01-26', 1, 'existMemberProfileImage', 999, 'ACTIVATE','1922-09-18 19:11:00.000000', '1922-09-18 19:11:00.000000'); +insert into `member` (`member_id`, `nickname`, `gender`, `birth`, `provide_id`, `status`, `created_at`, `updated_at`) +values (999, 'existMemberNickName', 'MALE', '2025-01-26', 999, 'ACTIVATE','1922-09-18 19:11:00.000000', '1922-09-18 19:11:00.000000'); -insert into `member` (`member_id`, `nickname`, `gender`, `birth`, `terms`, `profile_image_key`, `provide_id`, `status`, `created_at`, `updated_at`) -values (1, 'createdMemberNickName', 'MALE', '2025-01-26', 1, 'existMemberProfileImage', 1, 'ACTIVATE','1922-09-18 19:11:00.000000', '1922-09-18 19:11:00.000000'); +insert into `member` (`member_id`, `nickname`, `gender`, `birth`, `provide_id`, `status`, `created_at`, `updated_at`) +values (1, 'createdMemberNickName', 'MALE', '2025-01-26', 1, 'ACTIVATE','1922-09-18 19:11:00.000000', '1922-09-18 19:11:00.000000'); insert into `provide` (`provide_id`, `provider`, `provided_id`, `email`, `member_id`) values (999, 'GOOGLE', 'test_provided_id', 'test_email', 999); diff --git a/src/test/resources/sql/createMemberTestData.sql b/src/test/resources/sql/createMemberTestData.sql index 224330d..ae0eedd 100644 --- a/src/test/resources/sql/createMemberTestData.sql +++ b/src/test/resources/sql/createMemberTestData.sql @@ -1,8 +1,8 @@ truncate table `member`; truncate table `provide`; -insert into `member` (`member_id`, `nickname`, `gender`, `birth`, `terms`, `profile_image_key`, `provide_id`, `status`,`created_at`, `updated_at`) -values (999, 'testMemberNickName', 'MALE', '2025-01-26', 1, 'testMemberProfileImage', 1, 'ACTIVATE','1922-09-18 19:11:00.000000', '1922-09-18 19:11:00.000000'); +insert into `member` (`member_id`, `nickname`, `gender`, `birth`, `provide_id`, `status`,`created_at`, `updated_at`) +values (999, 'testMemberNickName', 'MALE', '2025-01-26', 1, 'ACTIVATE','1922-09-18 19:11:00.000000', '1922-09-18 19:11:00.000000'); insert into `provide` (`provide_id`, `provider`, `provided_id`, `email`, `member_id`) values (1, 'GOOGLE', 'testMemberProvidedId', 'testMemberEmail', 999); \ No newline at end of file