diff --git a/.gitignore b/.gitignore index e683fba5..a79f1a9f 100644 --- a/.gitignore +++ b/.gitignore @@ -7,3 +7,5 @@ module-common/build/ module-domain/build/ module-auth/build/ module-api/src/main/resources/application.yml + +module-domain/src/test/resources/application.yml diff --git a/module-api/build.gradle b/module-api/build.gradle index aa8bf94d..63fe5ae3 100644 --- a/module-api/build.gradle +++ b/module-api/build.gradle @@ -15,6 +15,9 @@ dependencies { implementation group: 'io.jsonwebtoken', name: 'jjwt-api', version: '0.11.5' implementation group: 'io.jsonwebtoken', name: 'jjwt-impl', version: '0.11.5' implementation group: 'io.jsonwebtoken', name: 'jjwt-jackson', version: '0.11.5' + + //Sentry + implementation 'io.sentry:sentry-spring-boot-starter-jakarta:7.9.0' } tasks.named('test') { diff --git a/module-api/src/main/java/com/mile/common/auth/JwtTokenProvider.java b/module-api/src/main/java/com/mile/common/auth/JwtTokenProvider.java index f981dc52..db14b227 100644 --- a/module-api/src/main/java/com/mile/common/auth/JwtTokenProvider.java +++ b/module-api/src/main/java/com/mile/common/auth/JwtTokenProvider.java @@ -1,8 +1,12 @@ package com.mile.common.auth; +import com.fasterxml.jackson.core.type.TypeReference; +import com.fasterxml.jackson.databind.ObjectMapper; import com.mile.exception.message.ErrorMessage; import com.mile.exception.model.BadRequestException; import com.mile.exception.model.UnauthorizedException; +import com.mile.writername.domain.MoimRole; +import com.mile.writername.service.vo.WriterNameInfo; import io.jsonwebtoken.Claims; import io.jsonwebtoken.ExpiredJwtException; import io.jsonwebtoken.Header; @@ -11,19 +15,26 @@ import io.jsonwebtoken.UnsupportedJwtException; import io.jsonwebtoken.security.Keys; import jakarta.annotation.PostConstruct; +import lombok.RequiredArgsConstructor; +import org.redisson.misc.Hash; import org.springframework.beans.factory.annotation.Value; -import org.springframework.stereotype.Service; +import org.springframework.stereotype.Component; import org.springframework.util.StringUtils; import javax.crypto.SecretKey; import java.nio.charset.StandardCharsets; import java.util.Base64; import java.util.Date; +import java.util.HashMap; +import java.util.Map; -@Service +@Component +@RequiredArgsConstructor public class JwtTokenProvider { + private final ObjectMapper objectMapper; private static final String MEMBER_ID = "memberId"; + private static final String JOINED_ROLE = "joinedRole"; private static final Long ACCESS_TOKEN_EXPIRATION_TIME = 4 * 60 * 60 * 1000L; private static final Long REFRESH_TOKEN_EXPIRATION_TIME = 60 * 60 * 24 * 1000L * 14; @@ -32,7 +43,6 @@ public class JwtTokenProvider { @PostConstruct protected void init() { - //base64 라이브러리에서 encodeToString을 이용해서 byte[] 형식을 String 형식으로 변환 JWT_SECRET = Base64.getEncoder().encodeToString(JWT_SECRET.getBytes(StandardCharsets.UTF_8)); } @@ -45,36 +55,39 @@ private String getTokenFromHeader(final String token) { return token.substring("Bearer ".length()); } - public String issueAccessToken(final Long userId) { - return issueToken(userId, ACCESS_TOKEN_EXPIRATION_TIME); + public String issueAccessToken(final Long userId, final Map joinedRole) { + return issueToken(userId, joinedRole, ACCESS_TOKEN_EXPIRATION_TIME); } - public String issueRefreshToken(final Long userId) { - return issueToken(userId, REFRESH_TOKEN_EXPIRATION_TIME); + public String issueRefreshToken(final Long userId, final Map joinedRole) { + return issueToken(userId, joinedRole, REFRESH_TOKEN_EXPIRATION_TIME); } private String issueToken( final Long userId, + final Map role, final Long expiredTime ) { final Date now = new Date(); final Claims claims = Jwts.claims() .setIssuedAt(now) - .setExpiration(new Date(now.getTime() + expiredTime)); // 만료 시간 설정 + .setExpiration(new Date(now.getTime() + expiredTime)); claims.put(MEMBER_ID, userId); + claims.put(JOINED_ROLE, role); + return Jwts.builder() - .setHeaderParam(Header.TYPE, Header.JWT_TYPE) // Header - .setClaims(claims) // Claim - .signWith(getSigningKey()) // Signature + .setHeaderParam(Header.TYPE, Header.JWT_TYPE) + .setClaims(claims) + .signWith(getSigningKey()) .compact(); } private SecretKey getSigningKey() { - String encodedKey = Base64.getEncoder().encodeToString(JWT_SECRET.getBytes()); //SecretKey 통해 서명 생성 - return Keys.hmacShaKeyFor(encodedKey.getBytes()); //일반적으로 HMAC (Hash-based Message Authentication Code) 알고리즘 사용 + String encodedKey = Base64.getEncoder().encodeToString(JWT_SECRET.getBytes()); + return Keys.hmacShaKeyFor(encodedKey.getBytes()); } public JwtValidationType validateToken(final String token) { @@ -100,8 +113,19 @@ private Claims getBody(final String token) { .getBody(); } - public Long getUserFromJwt(final String token) { + public Long getUserFromAuthHeader(final String token) { Claims claims = getBody(getTokenFromHeader(token)); return Long.valueOf(claims.get(MEMBER_ID).toString()); } + + public HashMap getJoinedRoleFromHeader(final String token) { + return getJoinedRoleFromJwt(getTokenFromHeader(token)); + } + + public HashMap getJoinedRoleFromJwt(final String token) { + Claims claims = getBody(token); + Object joinedRole = claims.get(JOINED_ROLE); + HashMap roleMap = objectMapper.convertValue(joinedRole, new TypeReference>() {}); + return roleMap; + } } diff --git a/module-api/src/main/java/com/mile/common/auth/JwtTokenUpdater.java b/module-api/src/main/java/com/mile/common/auth/JwtTokenUpdater.java new file mode 100644 index 00000000..63526173 --- /dev/null +++ b/module-api/src/main/java/com/mile/common/auth/JwtTokenUpdater.java @@ -0,0 +1,36 @@ +package com.mile.common.auth; + +import com.mile.writername.service.vo.WriterNameInfo; +import com.mile.jwt.service.TokenService; +import com.mile.writername.domain.MoimRole; +import com.mile.writername.service.WriterNameRetriever; +import lombok.RequiredArgsConstructor; +import org.springframework.stereotype.Component; + +import java.util.Map; + +@Component +@RequiredArgsConstructor +public class JwtTokenUpdater { + + private final JwtTokenProvider jwtTokenProvider; + private final TokenService tokenService; + private final WriterNameRetriever writerNameRetriever; + + public String setAccessToken(final Long userId, final Long moimId, final Long writerNameId, final MoimRole moimRole) { + + Map moimRoleMap = writerNameRetriever.getJoinedRoleFromUserId(userId); + + tokenService.deleteRefreshToken(userId); + + moimRoleMap.put(moimId, WriterNameInfo.of(writerNameId, moimRole)); + + String newAccessToken = jwtTokenProvider.issueAccessToken(userId, moimRoleMap); + String newRefreshToken = jwtTokenProvider.issueRefreshToken(userId, moimRoleMap); + + tokenService.saveRefreshToken(userId, newRefreshToken); + + return newAccessToken; + } + +} diff --git a/module-api/src/main/java/com/mile/common/auth/annotation/UserAuthAnnotation.java b/module-api/src/main/java/com/mile/common/auth/annotation/UserAuthAnnotation.java new file mode 100644 index 00000000..76622296 --- /dev/null +++ b/module-api/src/main/java/com/mile/common/auth/annotation/UserAuthAnnotation.java @@ -0,0 +1,14 @@ +package com.mile.common.auth.annotation; + +import java.lang.annotation.Documented; +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +@Retention(RetentionPolicy.RUNTIME) +@Target({ElementType.METHOD}) +@Documented +public @interface UserAuthAnnotation { + UserAuthenticationType value() default UserAuthenticationType.USER; +} diff --git a/module-api/src/main/java/com/mile/common/auth/annotation/UserAuthenticationType.java b/module-api/src/main/java/com/mile/common/auth/annotation/UserAuthenticationType.java new file mode 100644 index 00000000..9d85b8d6 --- /dev/null +++ b/module-api/src/main/java/com/mile/common/auth/annotation/UserAuthenticationType.java @@ -0,0 +1,7 @@ +package com.mile.common.auth.annotation; + +public enum UserAuthenticationType { + OWNER, + WRITER_NAME, + USER +} diff --git a/module-api/src/main/java/com/mile/common/auth/dto/AccessTokenDto.java b/module-api/src/main/java/com/mile/common/auth/dto/AccessTokenDto.java new file mode 100644 index 00000000..8295490f --- /dev/null +++ b/module-api/src/main/java/com/mile/common/auth/dto/AccessTokenDto.java @@ -0,0 +1,13 @@ +package com.mile.common.auth.dto; + +public record AccessTokenDto( + String accessToken, + T response +) { + public static AccessTokenDto of(final T data, final String accessToken) { + return new AccessTokenDto<>(accessToken, data); + } + public static AccessTokenDto of(final String accessToken) { + return new AccessTokenDto(accessToken, null); + } +} diff --git a/module-api/src/main/java/com/mile/common/interceptor/MoimAuthInterceptor.java b/module-api/src/main/java/com/mile/common/interceptor/MoimAuthInterceptor.java new file mode 100644 index 00000000..fe2cafa6 --- /dev/null +++ b/module-api/src/main/java/com/mile/common/interceptor/MoimAuthInterceptor.java @@ -0,0 +1,96 @@ +package com.mile.common.interceptor; + +import com.mile.common.auth.JwtTokenProvider; +import com.mile.common.auth.annotation.UserAuthAnnotation; +import com.mile.common.utils.thread.WriterNameContextUtil; +import com.mile.common.utils.SecureUrlUtil; +import com.mile.exception.message.ErrorMessage; +import com.mile.exception.model.ForbiddenException; +import com.mile.exception.model.UnauthorizedException; +import com.mile.writername.domain.MoimRole; +import com.mile.writername.service.vo.WriterNameInfo; +import jakarta.servlet.http.HttpServletRequest; +import jakarta.servlet.http.HttpServletResponse; +import lombok.RequiredArgsConstructor; +import org.springframework.stereotype.Component; +import org.springframework.web.method.HandlerMethod; +import org.springframework.web.servlet.HandlerInterceptor; +import org.springframework.web.servlet.resource.ResourceHttpRequestHandler; + +import java.util.HashMap; +import java.util.Map; +import java.util.Objects; + +import static org.springframework.web.servlet.HandlerMapping.URI_TEMPLATE_VARIABLES_ATTRIBUTE; + +@Component +@RequiredArgsConstructor +public class MoimAuthInterceptor implements HandlerInterceptor { + + private static final String MOIM_ID = "moimId"; + private final JwtTokenProvider jwtTokenProvider; + private final SecureUrlUtil secureUrlUtil; + + @Override + public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) { + if (handler instanceof ResourceHttpRequestHandler || Objects.equals(request.getMethod(), "OPTIONS")) { + return true; + } + HandlerMethod method = (HandlerMethod) handler; + + UserAuthAnnotation annotation = method.getMethodAnnotation(UserAuthAnnotation.class); + + if (annotation != null) { + final String userToken = getUserTokenFromHeader(request); + + final HashMap roleFromUser = jwtTokenProvider.getJoinedRoleFromHeader(userToken); + final Map pathVariables = (Map) request.getAttribute(URI_TEMPLATE_VARIABLES_ATTRIBUTE); + + return authenticateUserFromMap(annotation, roleFromUser, pathVariables); + } + return true; + } + + private String getUserTokenFromHeader(final HttpServletRequest request) { + final String userToken = request.getHeader("Authorization"); + + if (userToken == null) { + throw new UnauthorizedException(ErrorMessage.UN_LOGIN_EXCEPTION); + } + + return userToken; + } + + private boolean authenticateUserFromMap(final UserAuthAnnotation annotation, + final HashMap userRoles, + final Map pathVariables) { + switch (annotation.value()) { + case OWNER -> { + final Long requestMoimId = secureUrlUtil.decodeUrl(pathVariables.get(MOIM_ID)); + if (!userRoles.containsKey(requestMoimId) || !userRoles.get(requestMoimId).moimRole().equals(MoimRole.OWNER)) { + throw new ForbiddenException(ErrorMessage.MOIM_OWNER_AUTHENTICATION_ERROR); + } + WriterNameContextUtil.setWriterNameIdContext(userRoles.get(requestMoimId).writerNameId()); + return true; + } + case WRITER_NAME -> { + final Long requestMoimId = secureUrlUtil.decodeUrl(pathVariables.get(MOIM_ID)); + if (!userRoles.containsKey(requestMoimId)) { + throw new ForbiddenException(ErrorMessage.USER_MOIM_AUTHENTICATE_ERROR); + } + WriterNameContextUtil.setWriterNameIdContext(userRoles.get(requestMoimId).writerNameId()); + return true; + } + case USER -> { + WriterNameContextUtil.setMoimWriterNameMapContext(userRoles); + return true; + } + } + return true; + } + + @Override + public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) { + WriterNameContextUtil.clear(); + } +} diff --git a/module-api/src/main/java/com/mile/common/resolver/comment/CommentVariableResolver.java b/module-api/src/main/java/com/mile/common/resolver/comment/CommentVariableResolver.java index 8d6750c0..7eb84751 100644 --- a/module-api/src/main/java/com/mile/common/resolver/comment/CommentVariableResolver.java +++ b/module-api/src/main/java/com/mile/common/resolver/comment/CommentVariableResolver.java @@ -2,7 +2,8 @@ import com.mile.exception.message.ErrorMessage; import com.mile.exception.model.BadRequestException; -import com.mile.utils.SecureUrlUtil; +import com.mile.common.utils.SecureUrlUtil; +import com.mile.exception.model.NotFoundException; import jakarta.servlet.http.HttpServletRequest; import lombok.RequiredArgsConstructor; import org.springframework.core.MethodParameter; @@ -36,7 +37,7 @@ public Object resolveArgument(MethodParameter parameter, ModelAndViewContainer m try { return secureUrlUtil.decodeUrl(id); } catch (NumberFormatException e) { - throw new BadRequestException(ErrorMessage.INVALID_URL_EXCEPTION); + throw new NotFoundException(ErrorMessage.INVALID_URL_EXCEPTION); } } } diff --git a/module-api/src/main/java/com/mile/common/resolver/moim/MoimVariableResolver.java b/module-api/src/main/java/com/mile/common/resolver/moim/MoimVariableResolver.java index 7b34ca39..95fb0071 100644 --- a/module-api/src/main/java/com/mile/common/resolver/moim/MoimVariableResolver.java +++ b/module-api/src/main/java/com/mile/common/resolver/moim/MoimVariableResolver.java @@ -2,7 +2,8 @@ import com.mile.exception.message.ErrorMessage; import com.mile.exception.model.BadRequestException; -import com.mile.utils.SecureUrlUtil; +import com.mile.common.utils.SecureUrlUtil; +import com.mile.exception.model.NotFoundException; import jakarta.servlet.http.HttpServletRequest; import lombok.RequiredArgsConstructor; import org.springframework.core.MethodParameter; @@ -36,7 +37,7 @@ public Object resolveArgument(MethodParameter parameter, ModelAndViewContainer m try { return secureUrlUtil.decodeUrl(moimId); } catch (NumberFormatException e) { - throw new BadRequestException(ErrorMessage.INVALID_URL_EXCEPTION); + throw new NotFoundException(ErrorMessage.INVALID_URL_EXCEPTION); } } } diff --git a/module-api/src/main/java/com/mile/common/resolver/post/PostVariableResolver.java b/module-api/src/main/java/com/mile/common/resolver/post/PostVariableResolver.java index 02562c51..a93b31d7 100644 --- a/module-api/src/main/java/com/mile/common/resolver/post/PostVariableResolver.java +++ b/module-api/src/main/java/com/mile/common/resolver/post/PostVariableResolver.java @@ -2,7 +2,8 @@ import com.mile.exception.message.ErrorMessage; import com.mile.exception.model.BadRequestException; -import com.mile.utils.SecureUrlUtil; +import com.mile.common.utils.SecureUrlUtil; +import com.mile.exception.model.NotFoundException; import jakarta.servlet.http.HttpServletRequest; import lombok.RequiredArgsConstructor; import org.springframework.core.MethodParameter; @@ -35,7 +36,7 @@ public Object resolveArgument(MethodParameter parameter, ModelAndViewContainer m try { return secureUrlUtil.decodeUrl(postId); } catch (NumberFormatException e) { - throw new BadRequestException(ErrorMessage.INVALID_URL_EXCEPTION); + throw new NotFoundException(ErrorMessage.INVALID_URL_EXCEPTION); } } } diff --git a/module-api/src/main/java/com/mile/common/resolver/reply/ReplyVariableResolver.java b/module-api/src/main/java/com/mile/common/resolver/reply/ReplyVariableResolver.java index d65deab9..3cecf8b5 100644 --- a/module-api/src/main/java/com/mile/common/resolver/reply/ReplyVariableResolver.java +++ b/module-api/src/main/java/com/mile/common/resolver/reply/ReplyVariableResolver.java @@ -2,7 +2,8 @@ import com.mile.exception.message.ErrorMessage; import com.mile.exception.model.BadRequestException; -import com.mile.utils.SecureUrlUtil; +import com.mile.common.utils.SecureUrlUtil; +import com.mile.exception.model.NotFoundException; import jakarta.servlet.http.HttpServletRequest; import lombok.RequiredArgsConstructor; import org.springframework.core.MethodParameter; @@ -36,7 +37,7 @@ public Object resolveArgument(MethodParameter parameter, ModelAndViewContainer m try { return secureUrlUtil.decodeUrl(replyId); } catch (NumberFormatException e) { - throw new BadRequestException(ErrorMessage.INVALID_URL_EXCEPTION); + throw new NotFoundException(ErrorMessage.INVALID_URL_EXCEPTION); } } } \ No newline at end of file diff --git a/module-api/src/main/java/com/mile/common/resolver/topic/TopicVariableResolver.java b/module-api/src/main/java/com/mile/common/resolver/topic/TopicVariableResolver.java index 3fc85a6d..42de6c25 100644 --- a/module-api/src/main/java/com/mile/common/resolver/topic/TopicVariableResolver.java +++ b/module-api/src/main/java/com/mile/common/resolver/topic/TopicVariableResolver.java @@ -2,7 +2,8 @@ import com.mile.exception.message.ErrorMessage; import com.mile.exception.model.BadRequestException; -import com.mile.utils.SecureUrlUtil; +import com.mile.common.utils.SecureUrlUtil; +import com.mile.exception.model.NotFoundException; import jakarta.servlet.http.HttpServletRequest; import lombok.RequiredArgsConstructor; import org.springframework.core.MethodParameter; @@ -36,7 +37,7 @@ public Object resolveArgument(MethodParameter parameter, ModelAndViewContainer m try { return secureUrlUtil.decodeUrl(topicId); } catch (NumberFormatException e) { - throw new BadRequestException(ErrorMessage.INVALID_URL_EXCEPTION); + throw new NotFoundException(ErrorMessage.INVALID_URL_EXCEPTION); } } } diff --git a/module-api/src/main/java/com/mile/common/resolver/user/UserIdHeaderResolver.java b/module-api/src/main/java/com/mile/common/resolver/user/UserIdHeaderResolver.java index 4f8bec0c..b6e91976 100644 --- a/module-api/src/main/java/com/mile/common/resolver/user/UserIdHeaderResolver.java +++ b/module-api/src/main/java/com/mile/common/resolver/user/UserIdHeaderResolver.java @@ -39,7 +39,7 @@ public Long resolveArgument(@NotNull MethodParameter parameter, ModelAndViewCont throw new UnauthorizedException(ErrorMessage.TOKEN_VALIDATION_ERROR); } - return jwtTokenProvider.getUserFromJwt(token); + return jwtTokenProvider.getUserFromAuthHeader(token); } } \ No newline at end of file diff --git a/module-api/src/main/java/com/mile/common/utils/ContextHolderUtil.java b/module-api/src/main/java/com/mile/common/utils/ContextHolderUtil.java index 8033880d..a9a4dabf 100644 --- a/module-api/src/main/java/com/mile/common/utils/ContextHolderUtil.java +++ b/module-api/src/main/java/com/mile/common/utils/ContextHolderUtil.java @@ -32,7 +32,7 @@ public String getUserIdFromContextHolder() { throw new UnauthorizedException(ErrorMessage.TOKEN_VALIDATION_ERROR); } - return jwtTokenProvider.getUserFromJwt(token).toString(); + return jwtTokenProvider.getUserFromAuthHeader(token).toString(); } } diff --git a/module-api/src/main/java/com/mile/common/utils/thread/WriterNameContextUtil.java b/module-api/src/main/java/com/mile/common/utils/thread/WriterNameContextUtil.java new file mode 100644 index 00000000..2bc28250 --- /dev/null +++ b/module-api/src/main/java/com/mile/common/utils/thread/WriterNameContextUtil.java @@ -0,0 +1,27 @@ +package com.mile.common.utils.thread; + +import com.mile.writername.service.vo.WriterNameInfo; + +import java.util.HashMap; + +public class WriterNameContextUtil { + private static final ThreadLocal writerNameContext = new ThreadLocal<>(); + private static final ThreadLocal> moimWriterNameMapContext = new ThreadLocal<>(); + + public static void setMoimWriterNameMapContext(HashMap moimInfoMap) { + moimWriterNameMapContext.set(moimInfoMap); + } + + public static void setWriterNameIdContext(Long writerNameId) { + writerNameContext.set(writerNameId); + } + + public static Long getWriterNameContext() { + return writerNameContext.get(); + } + public static HashMap getMoimWriterNameMapContext() {return moimWriterNameMapContext.get();} + + public static void clear() { + writerNameContext.remove(); + } +} diff --git a/module-api/src/main/java/com/mile/config/WebConfig.java b/module-api/src/main/java/com/mile/config/WebConfig.java index 2dce679e..110e5685 100644 --- a/module-api/src/main/java/com/mile/config/WebConfig.java +++ b/module-api/src/main/java/com/mile/config/WebConfig.java @@ -2,6 +2,7 @@ import com.mile.common.interceptor.DuplicatedInterceptor; +import com.mile.common.interceptor.MoimAuthInterceptor; import com.mile.common.resolver.comment.CommentVariableResolver; import com.mile.common.resolver.moim.MoimVariableResolver; import com.mile.common.resolver.post.PostVariableResolver; @@ -27,6 +28,7 @@ public class WebConfig implements WebMvcConfigurer { private final CommentVariableResolver commentVariableResolver; private final ReplyVariableResolver replyVariableResolver; private final DuplicatedInterceptor duplicatedInterceptor; + private final MoimAuthInterceptor moimAuthInterceptor; private final UserIdHeaderResolver userIdHeaderResolver; @Value("${client.local}") @@ -59,7 +61,8 @@ public void addCorsMappings(CorsRegistry registry) { @Override public void addInterceptors(InterceptorRegistry registry) { registry.addInterceptor(duplicatedInterceptor) - .addPathPatterns("/api/post/temporary", "/api/post", "/api/post/{postId}/comment","/api/comment/{commentId}", "/api/moim/{moimId}/topic"); + .addPathPatterns("/api/post/temporary", "/api/post", "/api/post/{postId}/comment", "/api/comment/{commentId}", "/api/moim/{moimId}/topic"); + registry.addInterceptor(moimAuthInterceptor); } @Override diff --git a/module-api/src/main/java/com/mile/controller/moim/MoimController.java b/module-api/src/main/java/com/mile/controller/moim/MoimController.java index 222dcaa0..1d4a0ec7 100644 --- a/module-api/src/main/java/com/mile/controller/moim/MoimController.java +++ b/module-api/src/main/java/com/mile/controller/moim/MoimController.java @@ -1,33 +1,42 @@ package com.mile.controller.moim; +import com.mile.common.auth.JwtTokenUpdater; +import com.mile.common.auth.annotation.UserAuthAnnotation; +import com.mile.common.auth.annotation.UserAuthenticationType; +import com.mile.common.auth.dto.AccessTokenDto; import com.mile.common.resolver.moim.MoimIdPathVariable; import com.mile.common.resolver.user.UserId; +import com.mile.common.utils.thread.WriterNameContextUtil; import com.mile.dto.SuccessResponse; import com.mile.exception.message.SuccessMessage; import com.mile.moim.service.MoimService; +import com.mile.moim.service.dto.MoimIdValueDto; +import com.mile.moim.service.dto.request.MoimCreateRequest; +import com.mile.moim.service.dto.request.MoimInfoModifyRequest; +import com.mile.moim.service.dto.request.TopicCreateRequest; +import com.mile.moim.service.dto.request.WriterMemberJoinRequest; import com.mile.moim.service.dto.response.BestMoimListResponse; import com.mile.moim.service.dto.response.ContentListResponse; import com.mile.moim.service.dto.response.InvitationCodeGetResponse; import com.mile.moim.service.dto.response.MoimAuthenticateResponse; -import com.mile.moim.service.dto.request.MoimCreateRequest; -import com.mile.moim.service.dto.response.MoimCreateResponse; import com.mile.moim.service.dto.response.MoimCuriousPostListResponse; -import com.mile.moim.service.dto.request.MoimInfoModifyRequest; import com.mile.moim.service.dto.response.MoimInfoOwnerResponse; import com.mile.moim.service.dto.response.MoimInfoResponse; import com.mile.moim.service.dto.response.MoimInvitationInfoResponse; +import com.mile.moim.service.dto.response.MoimMostCuriousWriterResponse; import com.mile.moim.service.dto.response.MoimNameConflictCheckResponse; import com.mile.moim.service.dto.response.MoimPublicStatusResponse; import com.mile.moim.service.dto.response.MoimTopicInfoListResponse; import com.mile.moim.service.dto.response.MoimTopicResponse; import com.mile.moim.service.dto.response.MoimWriterNameListGetResponse; -import com.mile.moim.service.dto.response.PopularWriterListResponse; import com.mile.moim.service.dto.response.TemporaryPostExistResponse; -import com.mile.moim.service.dto.request.TopicCreateRequest; import com.mile.moim.service.dto.response.TopicListResponse; -import com.mile.moim.service.dto.request.WriterMemberJoinRequest; import com.mile.moim.service.dto.response.WriterNameConflictCheckResponse; -import com.mile.writername.service.dto.response.WriterNameShortResponse; +import com.mile.writername.domain.MoimRole; +import com.mile.writername.service.dto.response.WriterNameInformationResponse; +import io.swagger.v3.oas.annotations.Parameter; +import io.swagger.v3.oas.annotations.enums.ParameterIn; +import io.swagger.v3.oas.annotations.media.Schema; import jakarta.validation.Valid; import lombok.RequiredArgsConstructor; import org.springframework.http.HttpStatus; @@ -50,16 +59,18 @@ public class MoimController implements MoimControllerSwagger { private final MoimService moimService; + private final JwtTokenUpdater jwtTokenUpdater; @Override @GetMapping("/{moimId}") + @UserAuthAnnotation(UserAuthenticationType.WRITER_NAME) public SuccessResponse getTopicsFromMoim( @MoimIdPathVariable final Long moimId, @UserId final Long userId, @PathVariable("moimId") final String moimUrl ) { return SuccessResponse.of(SuccessMessage.TOPIC_SEARCH_SUCCESS, - moimService.getContentsFromMoim(moimId, userId)); + moimService.getContentsFromMoim(moimId)); } @@ -75,16 +86,18 @@ public ResponseEntity> checkCon } @Override - @PostMapping("{moimId}/user") + @PostMapping("/{moimId}/user") public ResponseEntity joinMoim( @MoimIdPathVariable final Long moimId, @RequestBody @Valid final WriterMemberJoinRequest joinRequest, @UserId final Long userId, @PathVariable("moimId") final String moimUrl ) { - return ResponseEntity.created(URI.create( - moimService.joinMoim(moimId, userId, joinRequest).toString())) - .body(SuccessResponse.of(SuccessMessage.WRITER_JOIN_SUCCESS)); + final Long writerNameId = moimService.joinMoim(moimId, userId, joinRequest); + return ResponseEntity + .ok(SuccessResponse.of(SuccessMessage.WRITER_JOIN_SUCCESS, + AccessTokenDto.of(jwtTokenUpdater.setAccessToken(userId, moimId, writerNameId, MoimRole.WRITER) + ))); } @Override @@ -112,7 +125,7 @@ public SuccessResponse getAuthenticationOfMoim( @Override @GetMapping("/{moimId}/writers/top-rank") - public ResponseEntity> getMostCuriousWritersOfMoim( + public ResponseEntity> getMostCuriousWritersOfMoim( @MoimIdPathVariable final Long moimId, @PathVariable("moimId") final String moimUrl ) { @@ -163,12 +176,13 @@ public SuccessResponse getMostCuriousPostByMoim( @Override @GetMapping("/{moimId}/info/owner") + @UserAuthAnnotation(UserAuthenticationType.OWNER) public ResponseEntity> getMoimInfoForOwner( @MoimIdPathVariable final Long moimId, @UserId final Long userId, @PathVariable("moimId") final String moimUrl ) { - return ResponseEntity.ok(SuccessResponse.of(SuccessMessage.MOIM_INFO_FOR_OWNER_GET_SUCCESS, moimService.getMoimInfoForOwner(moimId, userId))); + return ResponseEntity.ok(SuccessResponse.of(SuccessMessage.MOIM_INFO_FOR_OWNER_GET_SUCCESS, moimService.getMoimInfoForOwner(moimId))); } @Override @@ -234,11 +248,19 @@ public ResponseEntity> validateMo @PostMapping @Override - public ResponseEntity> createMoim( + public ResponseEntity> createMoim( @RequestBody @Valid final MoimCreateRequest creatRequest, @UserId final Long userId ) { - return ResponseEntity.ok(SuccessResponse.of(SuccessMessage.MOIM_CREATE_SUCCESS, moimService.createMoim(userId, creatRequest))); + MoimIdValueDto moimIdValueDto = moimService.createMoim(userId, creatRequest); + return ResponseEntity.ok( + SuccessResponse.of( + SuccessMessage.MOIM_CREATE_SUCCESS, + AccessTokenDto.of( + moimIdValueDto.data(), + jwtTokenUpdater.setAccessToken(userId, moimIdValueDto.moimId(), moimIdValueDto.writerNameId(), MoimRole.OWNER)) + ) + ); } @GetMapping("/{moimId}/invitation-code") @@ -263,13 +285,13 @@ public ResponseEntity> getWriterN } @Override + @UserAuthAnnotation(UserAuthenticationType.WRITER_NAME) @GetMapping("/{moimId}/writername") - public ResponseEntity> getWriterNameOfUser( + public ResponseEntity> getWriterNameOfUser( @MoimIdPathVariable final Long moimId, - @UserId final Long userId, @PathVariable("moimId") final String moimUrl ) { - return ResponseEntity.ok(SuccessResponse.of(SuccessMessage.WRITER_NAME_GET_SUCCESS, moimService.getWriterNameOfUser(moimId, userId))); + return ResponseEntity.ok(SuccessResponse.of(SuccessMessage.WRITER_NAME_GET_SUCCESS, moimService.getWriterNameOfUser(WriterNameContextUtil.getWriterNameContext()))); } @Override @@ -293,4 +315,12 @@ public ResponseEntity deleteMoim( return ResponseEntity.ok(SuccessResponse.of(SuccessMessage.MOIM_DELETE_SUCCESS)); } + @Override + @GetMapping("/{moimId}/information") + public ResponseEntity getMoimTotalInformation( + @MoimIdPathVariable @Parameter(schema = @Schema(implementation = String.class), in = ParameterIn.PATH) final Long moimId, + @PathVariable("moimId") final String moimUrl + ) { + return ResponseEntity.ok(SuccessResponse.of(SuccessMessage.MOIM_INFO_SUCCESS, moimService.getMoimTotalInformation(moimId))); + } } diff --git a/module-api/src/main/java/com/mile/controller/moim/MoimControllerSwagger.java b/module-api/src/main/java/com/mile/controller/moim/MoimControllerSwagger.java index aec51e01..e0aa0141 100644 --- a/module-api/src/main/java/com/mile/controller/moim/MoimControllerSwagger.java +++ b/module-api/src/main/java/com/mile/controller/moim/MoimControllerSwagger.java @@ -1,5 +1,6 @@ package com.mile.controller.moim; +import com.mile.common.auth.dto.AccessTokenDto; import com.mile.common.resolver.moim.MoimIdPathVariable; import com.mile.common.resolver.user.UserId; import com.mile.dto.ErrorResponse; @@ -8,7 +9,6 @@ import com.mile.moim.service.dto.response.ContentListResponse; import com.mile.moim.service.dto.response.InvitationCodeGetResponse; import com.mile.moim.service.dto.request.MoimCreateRequest; -import com.mile.moim.service.dto.response.MoimCreateResponse; import com.mile.moim.service.dto.response.MoimCuriousPostListResponse; import com.mile.moim.service.dto.request.MoimInfoModifyRequest; import com.mile.moim.service.dto.response.MoimInfoOwnerResponse; @@ -18,13 +18,13 @@ import com.mile.moim.service.dto.response.MoimTopicInfoListResponse; import com.mile.moim.service.dto.response.MoimTopicResponse; import com.mile.moim.service.dto.response.MoimWriterNameListGetResponse; -import com.mile.moim.service.dto.response.PopularWriterListResponse; +import com.mile.moim.service.dto.response.MoimMostCuriousWriterResponse; import com.mile.moim.service.dto.response.TemporaryPostExistResponse; import com.mile.moim.service.dto.request.TopicCreateRequest; import com.mile.moim.service.dto.response.TopicListResponse; import com.mile.moim.service.dto.request.WriterMemberJoinRequest; import com.mile.moim.service.dto.response.WriterNameConflictCheckResponse; -import com.mile.writername.service.dto.response.WriterNameShortResponse; +import com.mile.writername.service.dto.response.WriterNameInformationResponse; import io.swagger.v3.oas.annotations.Operation; import io.swagger.v3.oas.annotations.Parameter; import io.swagger.v3.oas.annotations.enums.ParameterIn; @@ -85,7 +85,7 @@ SuccessResponse getAuthenticationOfMoim( content = @Content(schema = @Schema(implementation = ErrorResponse.class))) } ) - ResponseEntity> getMostCuriousWritersOfMoim( + ResponseEntity> getMostCuriousWritersOfMoim( @Parameter(schema = @Schema(implementation = String.class), in = ParameterIn.PATH) final Long moimId, @PathVariable("moimId") final String moimUrl ); @@ -309,7 +309,7 @@ ResponseEntity> getInvitationCode( content = @Content(schema = @Schema(implementation = ErrorResponse.class))) } ) - ResponseEntity> createMoim( + ResponseEntity> createMoim( @RequestBody final MoimCreateRequest creatRequest, @Parameter(schema = @Schema(implementation = String.class), in = ParameterIn.PATH) final @UserId Long userId ); @@ -394,9 +394,8 @@ ResponseEntity> getWriterNameList content = @Content(schema = @Schema(implementation = ErrorResponse.class))) } ) - ResponseEntity> getWriterNameOfUser( + ResponseEntity> getWriterNameOfUser( @Parameter(schema = @Schema(implementation = String.class), in = ParameterIn.PATH) final Long moimId, - @Parameter(schema = @Schema(implementation = String.class), in = ParameterIn.PATH) final @UserId Long userId, @PathVariable("moimId") final String moimUrl ); @@ -430,4 +429,18 @@ ResponseEntity deleteMoim( @Parameter(schema = @Schema(implementation = String.class), in = ParameterIn.PATH) @UserId final Long userId, @PathVariable("moimId") final String moimUrl ); + + @Operation(summary = "글모임 정보, 가장 궁금한 글, 가장 궁금한 작가") + @ApiResponses( + value = { + @ApiResponse(responseCode = "200", description = "글모임의 개괄적인 정보가 조회되었습니다."), + @ApiResponse(responseCode = "404", description = "해당 모임은 존재하지 않습니다."), + @ApiResponse(responseCode = "500", description = "서버 내부 오류입니다.", + content = @Content(schema = @Schema(implementation = ErrorResponse.class))) + } + ) + ResponseEntity getMoimTotalInformation( + @Parameter(schema = @Schema(implementation = String.class), in = ParameterIn.PATH) final Long moimId, + @PathVariable("moimId") final String moimUrl + ); } diff --git a/module-api/src/main/java/com/mile/controller/post/PostController.java b/module-api/src/main/java/com/mile/controller/post/PostController.java index f397708d..f56bb1d1 100644 --- a/module-api/src/main/java/com/mile/controller/post/PostController.java +++ b/module-api/src/main/java/com/mile/controller/post/PostController.java @@ -1,6 +1,9 @@ package com.mile.controller.post; +import com.mile.common.auth.annotation.UserAuthAnnotation; +import com.mile.common.auth.annotation.UserAuthenticationType; import com.mile.common.resolver.user.UserId; +import com.mile.common.utils.thread.WriterNameContextUtil; import com.mile.curious.service.dto.CuriousInfoResponse; import com.mile.dto.SuccessResponse; import com.mile.exception.message.SuccessMessage; @@ -39,15 +42,15 @@ public class PostController implements PostControllerSwagger { @PostMapping("/{postId}/comment") @Override + @UserAuthAnnotation(UserAuthenticationType.USER) public SuccessResponse postComment( @PostIdPathVariable final Long postId, @Valid @RequestBody final CommentCreateRequest commentCreateRequest, - @UserId final Long userId, @PathVariable("postId") final String postUrl ) { postService.createCommentOnPost( postId, - userId, + WriterNameContextUtil.getMoimWriterNameMapContext(), commentCreateRequest ); return SuccessResponse.of(SuccessMessage.COMMENT_CREATE_SUCCESS); @@ -56,43 +59,51 @@ public SuccessResponse postComment( @PostMapping("/{postId}/curious") @Override + @UserAuthAnnotation(UserAuthenticationType.USER) public SuccessResponse postCurious( @PostIdPathVariable final Long postId, - @UserId final Long userId, @PathVariable("postId") final String postUrl ) { - return SuccessResponse.of(SuccessMessage.CURIOUS_CREATE_SUCCESS, postService.createCuriousOnPost(postId, userId)); + return SuccessResponse.of(SuccessMessage.CURIOUS_CREATE_SUCCESS, postService.createCuriousOnPost(postId, WriterNameContextUtil.getMoimWriterNameMapContext())); } @GetMapping("/{postId}/comment") @Override + @UserAuthAnnotation(UserAuthenticationType.USER) public ResponseEntity> getComments( @PostIdPathVariable final Long postId, - @UserId Long userId, @PathVariable("postId") final String postUrl ) { - return ResponseEntity.ok(SuccessResponse.of(SuccessMessage.COMMENT_SEARCH_SUCCESS, postService.getComments(postId, userId))); + return ResponseEntity.ok(SuccessResponse.of(SuccessMessage.COMMENT_SEARCH_SUCCESS, postService.getComments(postId, WriterNameContextUtil.getMoimWriterNameMapContext()))); } @GetMapping("/{postId}/info/curious") @Override + @UserAuthAnnotation(UserAuthenticationType.USER) public ResponseEntity> getCuriousInfo( @PostIdPathVariable final Long postId, - @UserId final Long userId, @PathVariable("postId") final String postUrl ) { - return ResponseEntity.status(HttpStatus.OK).body(SuccessResponse.of(SuccessMessage.CURIOUS_INFO_SEARCH_SUCCESS, postService.getCuriousInfoOfPost(postId, userId))); + return ResponseEntity.status(HttpStatus.OK).body(SuccessResponse.of(SuccessMessage.CURIOUS_INFO_SEARCH_SUCCESS, + postService.getCuriousInfoOfPost( + postId, + WriterNameContextUtil.getMoimWriterNameMapContext() + ))); } @DeleteMapping("/{postId}/curious") @Override + @UserAuthAnnotation(UserAuthenticationType.USER) public SuccessResponse deleteCurious( @PostIdPathVariable final Long postId, - @UserId final Long userId, @PathVariable("postId") final String postUrl ) { - return SuccessResponse.of(SuccessMessage.CURIOUS_DELETE_SUCCESS, postService.deleteCuriousOnPost(postId, userId)); + return SuccessResponse.of(SuccessMessage.CURIOUS_DELETE_SUCCESS, + postService.deleteCuriousOnPost( + postId, + WriterNameContextUtil.getMoimWriterNameMapContext() + )); } @GetMapping("/{postId}/authenticate") @@ -107,13 +118,13 @@ public ResponseEntity> getAuthenticate @PutMapping("/{postId}") @Override + @UserAuthAnnotation(UserAuthenticationType.USER) public ResponseEntity putPost( @PostIdPathVariable final Long postId, @Valid @RequestBody final PostPutRequest putRequest, - @UserId final Long userId, @PathVariable("postId") final String postUrl ) { - postService.updatePost(postId, userId, putRequest); + postService.updatePost(postId, WriterNameContextUtil.getMoimWriterNameMapContext(), putRequest); return ResponseEntity.status(HttpStatus.OK).body(SuccessResponse.of(SuccessMessage.POST_PUT_SUCCESS)); } @@ -130,13 +141,14 @@ public ResponseEntity deletePost( @Override @GetMapping("/temporary/{postId}") + @UserAuthAnnotation(UserAuthenticationType.USER) public SuccessResponse getTemporaryPost( @PostIdPathVariable final Long postId, - @UserId final Long userId, @PathVariable("postId") final String postUrl ) { return SuccessResponse.of(SuccessMessage.TEMPORARY_POST_GET_SUCCESS, - postService.getTemporaryPost(postId, userId)); + postService.getTemporaryPost(postId, + WriterNameContextUtil.getMoimWriterNameMapContext())); } @Override @@ -176,14 +188,14 @@ public SuccessResponse createTemporaryPost( @Override @DeleteMapping("/temporary/{postId}") + @UserAuthAnnotation(UserAuthenticationType.USER) public ResponseEntity deleteTemporaryPost( @PostIdPathVariable final Long postId, - @UserId final Long userId, @PathVariable("postId") final String postUrl ) { postService.deleteTemporaryPost( - userId, - postId + postId, + WriterNameContextUtil.getMoimWriterNameMapContext() ); return ResponseEntity.ok(SuccessResponse.of(SuccessMessage.TEMPORARY_POST_DELETE_SUCCESS)); } @@ -205,13 +217,13 @@ public ResponseEntity> putTemporaryToFixedPo @Override @GetMapping("/modify/{postId}") + @UserAuthAnnotation(UserAuthenticationType.USER) public SuccessResponse getPostForModifying( @PostIdPathVariable final Long postId, - @UserId final Long userId, @PathVariable("postId") final String postUrl ) { return SuccessResponse.of(SuccessMessage.MODIFY_POST_GET_SUCCESS, - postService.getPostForModifying(postId, userId)); + postService.getPostForModifying(postId, WriterNameContextUtil.getMoimWriterNameMapContext())); } } diff --git a/module-api/src/main/java/com/mile/controller/post/PostControllerSwagger.java b/module-api/src/main/java/com/mile/controller/post/PostControllerSwagger.java index 021cac42..bd2c9f80 100644 --- a/module-api/src/main/java/com/mile/controller/post/PostControllerSwagger.java +++ b/module-api/src/main/java/com/mile/controller/post/PostControllerSwagger.java @@ -48,7 +48,6 @@ public interface PostControllerSwagger { SuccessResponse postComment( @Parameter(schema = @Schema(implementation = String.class), in = ParameterIn.PATH) final Long postId, @Valid @RequestBody final CommentCreateRequest commentCreateRequest, - @Parameter(schema = @Schema(implementation = String.class), in = ParameterIn.PATH) @UserId final Long userId, @PathVariable("postId") final String postUrl ); @@ -65,7 +64,6 @@ SuccessResponse postComment( ) SuccessResponse postCurious( @Parameter(schema = @Schema(implementation = String.class), in = ParameterIn.PATH) final Long postId, - @Parameter(schema = @Schema(implementation = String.class), in = ParameterIn.PATH) @UserId final Long userId, @PathVariable("postId") final String postUrl ); @@ -83,7 +81,6 @@ SuccessResponse postCurious( ) ResponseEntity> getComments( @Parameter(schema = @Schema(implementation = String.class), in = ParameterIn.PATH) final Long postId, - @Parameter(schema = @Schema(implementation = String.class), in = ParameterIn.PATH) @UserId final Long userId, @PathVariable("postId") final String postUrl ); @@ -100,7 +97,6 @@ ResponseEntity> getComments( ) ResponseEntity> getCuriousInfo( @Parameter(schema = @Schema(implementation = String.class), in = ParameterIn.PATH) final Long postId, - @Parameter(schema = @Schema(implementation = String.class), in = ParameterIn.PATH) @UserId final Long userId, @PathVariable("postId") final String postUrl ); @@ -117,7 +113,6 @@ ResponseEntity> getCuriousInfo( ) SuccessResponse deleteCurious( @Parameter(schema = @Schema(implementation = String.class), in = ParameterIn.PATH) final Long postId, - @Parameter(schema = @Schema(implementation = String.class), in = ParameterIn.PATH) @UserId final Long userId, @PathVariable("postId") final String postUrl ); @@ -167,7 +162,6 @@ ResponseEntity> getAuthenticateWrite( ResponseEntity putPost( @Parameter(schema = @Schema(implementation = String.class), in = ParameterIn.PATH) final Long postId, @RequestBody final PostPutRequest putRequest, - @Parameter(schema = @Schema(implementation = String.class), in = ParameterIn.PATH) @UserId final Long userId, @PathVariable("postId") final String postUrl ); @@ -185,7 +179,6 @@ ResponseEntity putPost( ) ResponseEntity deleteTemporaryPost( @Parameter(schema = @Schema(implementation = String.class), in = ParameterIn.PATH) final Long postId, - @Parameter(schema = @Schema(implementation = String.class), in = ParameterIn.PATH) @UserId final Long userId, @PathVariable("postId") final String postUrl ); @@ -219,7 +212,6 @@ ResponseEntity deletePost( ) SuccessResponse getTemporaryPost( @Parameter(schema = @Schema(implementation = String.class), in = ParameterIn.PATH) final Long postId, - @Parameter(schema = @Schema(implementation = String.class), in = ParameterIn.PATH) @UserId final Long userId, @PathVariable("postId") final String postUrl ); @@ -312,7 +304,6 @@ ResponseEntity> putTemporaryToFixedPost( ) SuccessResponse getPostForModifying( @Parameter(schema = @Schema(implementation = String.class), in = ParameterIn.PATH) final Long postId, - @Parameter(schema = @Schema(implementation = String.class), in = ParameterIn.PATH) @UserId final Long userId, @PathVariable("postId") final String postUrl ); } diff --git a/module-api/src/main/java/com/mile/controller/user/UserController.java b/module-api/src/main/java/com/mile/controller/user/UserController.java index acccb26c..be29f4e5 100644 --- a/module-api/src/main/java/com/mile/controller/user/UserController.java +++ b/module-api/src/main/java/com/mile/controller/user/UserController.java @@ -1,6 +1,8 @@ package com.mile.controller.user; import com.mile.client.dto.UserLoginRequest; +import com.mile.common.auth.annotation.UserAuthAnnotation; +import com.mile.common.auth.annotation.UserAuthenticationType; import com.mile.common.resolver.user.UserId; import com.mile.controller.user.facade.AuthFacade; import com.mile.dto.SuccessResponse; @@ -55,6 +57,7 @@ public ResponseEntity> login( @GetMapping("/refresh-token") @Override + @UserAuthAnnotation(UserAuthenticationType.USER) public SuccessResponse refreshToken( @CookieValue(name = REFRESH_TOKEN) Cookie cookie ) { diff --git a/module-api/src/main/java/com/mile/controller/user/facade/AuthFacade.java b/module-api/src/main/java/com/mile/controller/user/facade/AuthFacade.java index 28a5fb83..bcdfe959 100644 --- a/module-api/src/main/java/com/mile/controller/user/facade/AuthFacade.java +++ b/module-api/src/main/java/com/mile/controller/user/facade/AuthFacade.java @@ -4,6 +4,7 @@ import com.mile.client.SocialType; import com.mile.client.dto.UserLoginRequest; import com.mile.common.auth.JwtTokenProvider; +import com.mile.writername.domain.MoimRole; import com.mile.jwt.service.TokenService; import com.mile.moim.service.dto.response.MoimListOfUserResponse; import com.mile.strategy.LoginStrategyManager; @@ -11,13 +12,17 @@ import com.mile.user.service.UserService; import com.mile.user.service.dto.AccessTokenGetSuccess; import com.mile.user.service.dto.LoginSuccessResponse; +import com.mile.writername.service.vo.WriterNameInfo; import lombok.AccessLevel; import lombok.RequiredArgsConstructor; import org.springframework.dao.DataIntegrityViolationException; import org.springframework.stereotype.Component; +import java.util.HashMap; +import java.util.Map; + @Component -@RequiredArgsConstructor(access = AccessLevel.PRIVATE) +@RequiredArgsConstructor(access = AccessLevel.PROTECTED) public class AuthFacade { private final UserService userService; @@ -29,9 +34,10 @@ public AccessTokenGetSuccess refreshToken( final String refreshToken ) { final Long userId = tokenService.findIdByRefreshToken(refreshToken); + final Map role = jwtTokenProvider.getJoinedRoleFromJwt(refreshToken); return AccessTokenGetSuccess.of( - jwtTokenProvider.issueAccessToken(userId) + jwtTokenProvider.issueAccessToken(userId, role) ); } @@ -42,8 +48,8 @@ public LoginSuccessResponse create( return getTokenDto(getUserInfoResponse(authorizationCode, loginRequest)); } - public void deleteUser(final Long userId, final String authoriztionCode, final UserLoginRequest userLoginRequest) { - revokeUser(authoriztionCode, userLoginRequest); + public void deleteUser(final Long userId, final String authorizationCode, final UserLoginRequest userLoginRequest) { + revokeUser(authorizationCode, userLoginRequest); userService.deleteUser(userId); tokenService.deleteRefreshToken(userId); } @@ -59,13 +65,15 @@ private LoginSuccessResponse getTokenDto( ) { try { if (userService.isExistingUser(userResponse.socialId(), userResponse.socialType())) { - return getTokenByUserId(userService.getBySocialId(userResponse.socialId(), userResponse.socialType()).getId()); + Long userId = userService.getBySocialId(userResponse.socialId(), userResponse.socialType()).getId(); + return getTokenByUserId(userId, userService.getJoinedRoleFromUser(userId)); } else { Long id = userService.createUser(userResponse.socialId(), userResponse.socialType(), userResponse.email()); - return getTokenByUserId(id); + return getTokenByUserId(id, new HashMap<>()); } } catch (DataIntegrityViolationException e) { - return getTokenByUserId(userService.getBySocialId(userResponse.socialId(), userResponse.socialType()).getId()); + Long userId = userService.getBySocialId(userResponse.socialId(), userResponse.socialType()).getId(); + return getTokenByUserId(userId, userService.getJoinedRoleFromUser(userId)); } } @@ -92,12 +100,13 @@ public UserInfoResponse getUserInfoResponse( public LoginSuccessResponse getTokenByUserId( - final Long id + final Long id, + final Map role ) { - String refreshToken = jwtTokenProvider.issueRefreshToken(id); + String refreshToken = jwtTokenProvider.issueRefreshToken(id, role); tokenService.saveRefreshToken(id, refreshToken); return LoginSuccessResponse.of( - jwtTokenProvider.issueAccessToken(id), + jwtTokenProvider.issueAccessToken(id, role), refreshToken ); } diff --git a/module-common/src/main/java/com/mile/handler/GlobalExceptionHandler.java b/module-api/src/main/java/com/mile/exception/handler/GlobalExceptionHandler.java similarity index 98% rename from module-common/src/main/java/com/mile/handler/GlobalExceptionHandler.java rename to module-api/src/main/java/com/mile/exception/handler/GlobalExceptionHandler.java index 9cc0513c..5ac7ab7c 100644 --- a/module-common/src/main/java/com/mile/handler/GlobalExceptionHandler.java +++ b/module-api/src/main/java/com/mile/exception/handler/GlobalExceptionHandler.java @@ -1,4 +1,4 @@ -package com.mile.handler; +package com.mile.exception.handler; import com.mile.dto.ErrorResponse; import com.mile.exception.message.ErrorMessage; @@ -70,7 +70,6 @@ public ResponseEntity handleJwtValidationException(final JwtValid @ExceptionHandler(HttpRequestMethodNotSupportedException.class) public ResponseEntity handleHttpRequestMethodNotSupportedException(final HttpRequestMethodNotSupportedException e) { - Sentry.captureException(e); return ResponseEntity.status(HttpStatus.METHOD_NOT_ALLOWED).body(ErrorResponse.of(ErrorMessage.METHOD_NOT_SUPPORTED)); } @@ -117,7 +116,6 @@ public ResponseEntity handleTooManyRequestException(final TooMany @ExceptionHandler(NoHandlerFoundException.class) public ResponseEntity handleNoHandlerFoundException(final NoHandlerFoundException e) { - Sentry.captureException(e); return ResponseEntity.status(HttpStatus.NOT_FOUND).body(ErrorResponse.of(ErrorMessage.HANDLER_NOT_FOUND)); } diff --git a/module-common/src/main/java/com/mile/log/aspect/LoggingAspect.java b/module-api/src/main/java/com/mile/exception/log/aspect/LoggingAspect.java similarity index 55% rename from module-common/src/main/java/com/mile/log/aspect/LoggingAspect.java rename to module-api/src/main/java/com/mile/exception/log/aspect/LoggingAspect.java index 1a3ef24e..85fad7f7 100644 --- a/module-common/src/main/java/com/mile/log/aspect/LoggingAspect.java +++ b/module-api/src/main/java/com/mile/exception/log/aspect/LoggingAspect.java @@ -1,7 +1,7 @@ -package com.mile.log.aspect; +package com.mile.exception.log.aspect; import com.fasterxml.jackson.databind.ObjectMapper; -import com.mile.log.filter.wrapper.CachedBodyRequestWrapper; +import com.mile.exception.log.filter.wrapper.CachedBodyRequestWrapper; import jakarta.servlet.http.HttpServletRequest; import lombok.extern.slf4j.Slf4j; import org.aspectj.lang.ProceedingJoinPoint; @@ -24,12 +24,34 @@ public class LoggingAspect { private final ObjectMapper objectMapper = new ObjectMapper(); - @Pointcut("execution(* com.mile.handler.GlobalExceptionHandler.handleException*(..))") + @Pointcut("execution(* com.mile.exception.handler.GlobalExceptionHandler.handleException*(..))") public void controllerErrorLevelExecute() { } + @Pointcut("execution(* com.mile.controller..*(..)) || ( execution(* com.mile.exception.handler..*(..)) && !execution(* com.mile.exception.handler.GlobalExceptionHandler.handleException*(..)))") + public void controllerInfoLevelExecute() { + } + + @Around("com.mile.exception.log.aspect.LoggingAspect.controllerInfoLevelExecute()") + public Object requestInfoLevelLogging(ProceedingJoinPoint proceedingJoinPoint) throws Throwable { + HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.currentRequestAttributes()).getRequest(); + final CachedBodyRequestWrapper cachedBodyRequestWrapper = new CachedBodyRequestWrapper(request); + long startAt = System.currentTimeMillis(); + Object returnValue = proceedingJoinPoint.proceed(proceedingJoinPoint.getArgs()); + long endAt = System.currentTimeMillis(); + log.info("================================================NEW==============================================="); + log.info("====> Request: {} {} ({}ms)\n *Header = {}", request.getMethod(), request.getRequestURL(), endAt - startAt, getHeaders(request)); + if ("POST".equalsIgnoreCase(request.getMethod())) { + log.info("====> Body: {}", objectMapper.readTree(cachedBodyRequestWrapper.getBody())); + } + if (returnValue != null) { + log.info("====> Response: {}", returnValue); + } + log.info("================================================END==============================================="); + return returnValue; + } - @Around("com.mile.log.aspect.LoggingAspect.controllerErrorLevelExecute()") + @Around("com.mile.exception.log.aspect.LoggingAspect.controllerErrorLevelExecute()") public Object requestErrorLevelLogging(ProceedingJoinPoint proceedingJoinPoint) throws Throwable { HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.currentRequestAttributes()).getRequest(); final CachedBodyRequestWrapper cachedBodyRequestWrapper = new CachedBodyRequestWrapper(request); diff --git a/module-common/src/main/java/com/mile/log/discord/DiscordAppender.java b/module-api/src/main/java/com/mile/exception/log/discord/DiscordAppender.java similarity index 94% rename from module-common/src/main/java/com/mile/log/discord/DiscordAppender.java rename to module-api/src/main/java/com/mile/exception/log/discord/DiscordAppender.java index 2af54e00..bcb0483e 100644 --- a/module-common/src/main/java/com/mile/log/discord/DiscordAppender.java +++ b/module-api/src/main/java/com/mile/exception/log/discord/DiscordAppender.java @@ -1,13 +1,13 @@ -package com.mile.log.discord; +package com.mile.exception.log.discord; import ch.qos.logback.classic.spi.ILoggingEvent; import ch.qos.logback.classic.spi.IThrowableProxy; import ch.qos.logback.classic.spi.ThrowableProxyUtil; import ch.qos.logback.core.UnsynchronizedAppenderBase; -import com.mile.log.discord.exception.ErrorLogAppenderException; -import com.mile.log.discord.model.EmbedObject; -import com.mile.log.utils.MDCUtil; -import com.mile.log.utils.StringUtil; +import com.mile.exception.log.discord.exception.ErrorLogAppenderException; +import com.mile.exception.log.discord.model.EmbedObject; +import com.mile.exception.log.utils.MDCUtil; +import com.mile.exception.log.utils.StringUtil; import lombok.Setter; import lombok.extern.slf4j.Slf4j; import org.apache.commons.lang3.StringEscapeUtils; diff --git a/module-common/src/main/java/com/mile/log/discord/DiscordWebHook.java b/module-api/src/main/java/com/mile/exception/log/discord/DiscordWebHook.java similarity index 89% rename from module-common/src/main/java/com/mile/log/discord/DiscordWebHook.java rename to module-api/src/main/java/com/mile/exception/log/discord/DiscordWebHook.java index 5d9aa288..1eaefa28 100644 --- a/module-common/src/main/java/com/mile/log/discord/DiscordWebHook.java +++ b/module-api/src/main/java/com/mile/exception/log/discord/DiscordWebHook.java @@ -1,15 +1,15 @@ -package com.mile.log.discord; - - -import com.mile.log.discord.exception.ErrorLogAppenderException; -import com.mile.log.discord.model.Author; -import com.mile.log.discord.model.EmbedObject; -import com.mile.log.discord.model.Field; -import com.mile.log.discord.model.Footer; -import com.mile.log.discord.model.Image; -import com.mile.log.discord.model.JsonObject; -import com.mile.log.discord.model.Thumbnail; -import com.mile.log.utils.ApiCallUtil; +package com.mile.exception.log.discord; + + +import com.mile.exception.log.discord.exception.ErrorLogAppenderException; +import com.mile.exception.log.discord.model.Author; +import com.mile.exception.log.discord.model.EmbedObject; +import com.mile.exception.log.discord.model.Field; +import com.mile.exception.log.discord.model.Footer; +import com.mile.exception.log.discord.model.JsonObject; +import com.mile.exception.log.discord.model.Thumbnail; +import com.mile.exception.log.utils.ApiCallUtil; +import com.mile.exception.log.discord.model.Image; import java.awt.Color; import java.io.IOException; diff --git a/module-common/src/main/java/com/mile/log/discord/exception/ErrorLogAppenderException.java b/module-api/src/main/java/com/mile/exception/log/discord/exception/ErrorLogAppenderException.java similarity index 84% rename from module-common/src/main/java/com/mile/log/discord/exception/ErrorLogAppenderException.java rename to module-api/src/main/java/com/mile/exception/log/discord/exception/ErrorLogAppenderException.java index d494fefd..554385a2 100644 --- a/module-common/src/main/java/com/mile/log/discord/exception/ErrorLogAppenderException.java +++ b/module-api/src/main/java/com/mile/exception/log/discord/exception/ErrorLogAppenderException.java @@ -1,4 +1,4 @@ -package com.mile.log.discord.exception; +package com.mile.exception.log.discord.exception; import com.mile.exception.message.ErrorMessage; import com.mile.exception.model.MileException; diff --git a/module-common/src/main/java/com/mile/log/discord/model/Author.java b/module-api/src/main/java/com/mile/exception/log/discord/model/Author.java similarity index 82% rename from module-common/src/main/java/com/mile/log/discord/model/Author.java rename to module-api/src/main/java/com/mile/exception/log/discord/model/Author.java index 4e060c29..3dc699f8 100644 --- a/module-common/src/main/java/com/mile/log/discord/model/Author.java +++ b/module-api/src/main/java/com/mile/exception/log/discord/model/Author.java @@ -1,4 +1,4 @@ -package com.mile.log.discord.model; +package com.mile.exception.log.discord.model; import lombok.Getter; import lombok.RequiredArgsConstructor; diff --git a/module-common/src/main/java/com/mile/log/discord/model/EmbedObject.java b/module-api/src/main/java/com/mile/exception/log/discord/model/EmbedObject.java similarity index 98% rename from module-common/src/main/java/com/mile/log/discord/model/EmbedObject.java rename to module-api/src/main/java/com/mile/exception/log/discord/model/EmbedObject.java index 5fe08acf..5ad41480 100644 --- a/module-common/src/main/java/com/mile/log/discord/model/EmbedObject.java +++ b/module-api/src/main/java/com/mile/exception/log/discord/model/EmbedObject.java @@ -1,4 +1,4 @@ -package com.mile.log.discord.model; +package com.mile.exception.log.discord.model; import java.awt.Color; import java.util.ArrayList; diff --git a/module-common/src/main/java/com/mile/log/discord/model/Field.java b/module-api/src/main/java/com/mile/exception/log/discord/model/Field.java similarity index 82% rename from module-common/src/main/java/com/mile/log/discord/model/Field.java rename to module-api/src/main/java/com/mile/exception/log/discord/model/Field.java index 83fa90a3..5e8cb355 100644 --- a/module-common/src/main/java/com/mile/log/discord/model/Field.java +++ b/module-api/src/main/java/com/mile/exception/log/discord/model/Field.java @@ -1,4 +1,4 @@ -package com.mile.log.discord.model; +package com.mile.exception.log.discord.model; import lombok.Getter; import lombok.RequiredArgsConstructor; diff --git a/module-common/src/main/java/com/mile/log/discord/model/Footer.java b/module-api/src/main/java/com/mile/exception/log/discord/model/Footer.java similarity index 80% rename from module-common/src/main/java/com/mile/log/discord/model/Footer.java rename to module-api/src/main/java/com/mile/exception/log/discord/model/Footer.java index 38f07725..5bc38e67 100644 --- a/module-common/src/main/java/com/mile/log/discord/model/Footer.java +++ b/module-api/src/main/java/com/mile/exception/log/discord/model/Footer.java @@ -1,4 +1,4 @@ -package com.mile.log.discord.model; +package com.mile.exception.log.discord.model; import lombok.Getter; import lombok.RequiredArgsConstructor; diff --git a/module-common/src/main/java/com/mile/log/discord/model/Image.java b/module-api/src/main/java/com/mile/exception/log/discord/model/Image.java similarity index 76% rename from module-common/src/main/java/com/mile/log/discord/model/Image.java rename to module-api/src/main/java/com/mile/exception/log/discord/model/Image.java index 9a1af728..9ee3f8c1 100644 --- a/module-common/src/main/java/com/mile/log/discord/model/Image.java +++ b/module-api/src/main/java/com/mile/exception/log/discord/model/Image.java @@ -1,4 +1,4 @@ -package com.mile.log.discord.model; +package com.mile.exception.log.discord.model; import lombok.Getter; diff --git a/module-common/src/main/java/com/mile/log/discord/model/JsonObject.java b/module-api/src/main/java/com/mile/exception/log/discord/model/JsonObject.java similarity index 97% rename from module-common/src/main/java/com/mile/log/discord/model/JsonObject.java rename to module-api/src/main/java/com/mile/exception/log/discord/model/JsonObject.java index 59fcbe98..18257fc4 100644 --- a/module-common/src/main/java/com/mile/log/discord/model/JsonObject.java +++ b/module-api/src/main/java/com/mile/exception/log/discord/model/JsonObject.java @@ -1,4 +1,4 @@ -package com.mile.log.discord.model; +package com.mile.exception.log.discord.model; import java.lang.reflect.Array; import java.util.HashMap; diff --git a/module-common/src/main/java/com/mile/log/discord/model/Thumbnail.java b/module-api/src/main/java/com/mile/exception/log/discord/model/Thumbnail.java similarity index 76% rename from module-common/src/main/java/com/mile/log/discord/model/Thumbnail.java rename to module-api/src/main/java/com/mile/exception/log/discord/model/Thumbnail.java index 0fae06cf..ed527e97 100644 --- a/module-common/src/main/java/com/mile/log/discord/model/Thumbnail.java +++ b/module-api/src/main/java/com/mile/exception/log/discord/model/Thumbnail.java @@ -1,4 +1,4 @@ -package com.mile.log.discord.model; +package com.mile.exception.log.discord.model; import lombok.Getter; import lombok.RequiredArgsConstructor; diff --git a/module-common/src/main/java/com/mile/log/filter/CustomServletWrappingFilter.java b/module-api/src/main/java/com/mile/exception/log/filter/CustomServletWrappingFilter.java similarity index 88% rename from module-common/src/main/java/com/mile/log/filter/CustomServletWrappingFilter.java rename to module-api/src/main/java/com/mile/exception/log/filter/CustomServletWrappingFilter.java index d993e03b..45a26e1e 100644 --- a/module-common/src/main/java/com/mile/log/filter/CustomServletWrappingFilter.java +++ b/module-api/src/main/java/com/mile/exception/log/filter/CustomServletWrappingFilter.java @@ -1,6 +1,6 @@ -package com.mile.log.filter; +package com.mile.exception.log.filter; -import com.mile.log.filter.wrapper.CachedBodyRequestWrapper; +import com.mile.exception.log.filter.wrapper.CachedBodyRequestWrapper; import jakarta.servlet.FilterChain; import jakarta.servlet.ServletException; import jakarta.servlet.http.HttpServletRequest; diff --git a/module-common/src/main/java/com/mile/log/filter/FilterConfig.java b/module-api/src/main/java/com/mile/exception/log/filter/FilterConfig.java similarity index 95% rename from module-common/src/main/java/com/mile/log/filter/FilterConfig.java rename to module-api/src/main/java/com/mile/exception/log/filter/FilterConfig.java index 33f6cc55..00880e39 100644 --- a/module-common/src/main/java/com/mile/log/filter/FilterConfig.java +++ b/module-api/src/main/java/com/mile/exception/log/filter/FilterConfig.java @@ -1,4 +1,4 @@ -package com.mile.log.filter; +package com.mile.exception.log.filter; import org.springframework.boot.web.servlet.FilterRegistrationBean; diff --git a/module-common/src/main/java/com/mile/log/filter/MDCFilter.java b/module-api/src/main/java/com/mile/exception/log/filter/MDCFilter.java similarity index 91% rename from module-common/src/main/java/com/mile/log/filter/MDCFilter.java rename to module-api/src/main/java/com/mile/exception/log/filter/MDCFilter.java index 8a6468fd..3f741f16 100644 --- a/module-common/src/main/java/com/mile/log/filter/MDCFilter.java +++ b/module-api/src/main/java/com/mile/exception/log/filter/MDCFilter.java @@ -1,7 +1,7 @@ -package com.mile.log.filter; +package com.mile.exception.log.filter; -import com.mile.log.utils.HttpRequestUtil; -import com.mile.log.utils.MDCUtil; +import com.mile.exception.log.utils.HttpRequestUtil; +import com.mile.exception.log.utils.MDCUtil; import jakarta.servlet.FilterChain; import jakarta.servlet.ServletException; import jakarta.servlet.http.HttpServletRequest; diff --git a/module-common/src/main/java/com/mile/log/filter/wrapper/CachedBodyRequestWrapper.java b/module-api/src/main/java/com/mile/exception/log/filter/wrapper/CachedBodyRequestWrapper.java similarity index 95% rename from module-common/src/main/java/com/mile/log/filter/wrapper/CachedBodyRequestWrapper.java rename to module-api/src/main/java/com/mile/exception/log/filter/wrapper/CachedBodyRequestWrapper.java index 956d1b5f..12ba71fe 100644 --- a/module-common/src/main/java/com/mile/log/filter/wrapper/CachedBodyRequestWrapper.java +++ b/module-api/src/main/java/com/mile/exception/log/filter/wrapper/CachedBodyRequestWrapper.java @@ -1,4 +1,4 @@ -package com.mile.log.filter.wrapper; +package com.mile.exception.log.filter.wrapper; import jakarta.servlet.ServletInputStream; import jakarta.servlet.http.HttpServletRequest; diff --git a/module-common/src/main/java/com/mile/log/filter/wrapper/CachedBodyServletInputStream.java b/module-api/src/main/java/com/mile/exception/log/filter/wrapper/CachedBodyServletInputStream.java similarity index 96% rename from module-common/src/main/java/com/mile/log/filter/wrapper/CachedBodyServletInputStream.java rename to module-api/src/main/java/com/mile/exception/log/filter/wrapper/CachedBodyServletInputStream.java index 75f31c0c..ffe5934a 100644 --- a/module-common/src/main/java/com/mile/log/filter/wrapper/CachedBodyServletInputStream.java +++ b/module-api/src/main/java/com/mile/exception/log/filter/wrapper/CachedBodyServletInputStream.java @@ -1,4 +1,4 @@ -package com.mile.log.filter.wrapper; +package com.mile.exception.log.filter.wrapper; import jakarta.servlet.ReadListener; import jakarta.servlet.ServletInputStream; diff --git a/module-common/src/main/java/com/mile/log/utils/ApiCallUtil.java b/module-api/src/main/java/com/mile/exception/log/utils/ApiCallUtil.java similarity index 92% rename from module-common/src/main/java/com/mile/log/utils/ApiCallUtil.java rename to module-api/src/main/java/com/mile/exception/log/utils/ApiCallUtil.java index 86a866bf..3dbbf00d 100644 --- a/module-common/src/main/java/com/mile/log/utils/ApiCallUtil.java +++ b/module-api/src/main/java/com/mile/exception/log/utils/ApiCallUtil.java @@ -1,4 +1,4 @@ -package com.mile.log.utils; +package com.mile.exception.log.utils; import java.io.IOException; @@ -6,7 +6,7 @@ import java.net.URL; import javax.net.ssl.HttpsURLConnection; -import com.mile.log.discord.model.JsonObject; +import com.mile.exception.log.discord.model.JsonObject; import lombok.AccessLevel; import lombok.NoArgsConstructor; import lombok.extern.slf4j.Slf4j; diff --git a/module-common/src/main/java/com/mile/log/utils/HttpRequestConfig.java b/module-api/src/main/java/com/mile/exception/log/utils/HttpRequestConfig.java similarity index 84% rename from module-common/src/main/java/com/mile/log/utils/HttpRequestConfig.java rename to module-api/src/main/java/com/mile/exception/log/utils/HttpRequestConfig.java index c56290ad..085da5bd 100644 --- a/module-common/src/main/java/com/mile/log/utils/HttpRequestConfig.java +++ b/module-api/src/main/java/com/mile/exception/log/utils/HttpRequestConfig.java @@ -1,6 +1,6 @@ -package com.mile.log.utils; +package com.mile.exception.log.utils; -import com.mile.log.filter.CustomServletWrappingFilter; +import com.mile.exception.log.filter.CustomServletWrappingFilter; import org.springframework.boot.web.servlet.FilterRegistrationBean; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; diff --git a/module-common/src/main/java/com/mile/log/utils/HttpRequestUtil.java b/module-api/src/main/java/com/mile/exception/log/utils/HttpRequestUtil.java similarity index 96% rename from module-common/src/main/java/com/mile/log/utils/HttpRequestUtil.java rename to module-api/src/main/java/com/mile/exception/log/utils/HttpRequestUtil.java index 2d79833b..06d5ca8b 100644 --- a/module-common/src/main/java/com/mile/log/utils/HttpRequestUtil.java +++ b/module-api/src/main/java/com/mile/exception/log/utils/HttpRequestUtil.java @@ -1,7 +1,7 @@ -package com.mile.log.utils; +package com.mile.exception.log.utils; -import com.mile.log.filter.wrapper.CachedBodyRequestWrapper; +import com.mile.exception.log.filter.wrapper.CachedBodyRequestWrapper; import jakarta.servlet.http.Cookie; import jakarta.servlet.http.HttpServletRequest; import lombok.AccessLevel; diff --git a/module-common/src/main/java/com/mile/log/utils/MDCUtil.java b/module-api/src/main/java/com/mile/exception/log/utils/MDCUtil.java similarity index 97% rename from module-common/src/main/java/com/mile/log/utils/MDCUtil.java rename to module-api/src/main/java/com/mile/exception/log/utils/MDCUtil.java index 816d32e4..c1ab2d0b 100644 --- a/module-common/src/main/java/com/mile/log/utils/MDCUtil.java +++ b/module-api/src/main/java/com/mile/exception/log/utils/MDCUtil.java @@ -1,4 +1,4 @@ -package com.mile.log.utils; +package com.mile.exception.log.utils; import com.fasterxml.jackson.core.JsonProcessingException; diff --git a/module-common/src/main/java/com/mile/log/utils/StringUtil.java b/module-api/src/main/java/com/mile/exception/log/utils/StringUtil.java similarity index 98% rename from module-common/src/main/java/com/mile/log/utils/StringUtil.java rename to module-api/src/main/java/com/mile/exception/log/utils/StringUtil.java index 85b5ce40..e6741fc6 100644 --- a/module-common/src/main/java/com/mile/log/utils/StringUtil.java +++ b/module-api/src/main/java/com/mile/exception/log/utils/StringUtil.java @@ -1,4 +1,4 @@ -package com.mile.log.utils; +package com.mile.exception.log.utils; import lombok.AccessLevel; import lombok.NoArgsConstructor; diff --git a/module-api/src/main/resources/discord-appender.xml b/module-api/src/main/resources/discord-appender.xml index 530e9fcd..74ccd739 100644 --- a/module-api/src/main/resources/discord-appender.xml +++ b/module-api/src/main/resources/discord-appender.xml @@ -1,5 +1,5 @@ - + ${DISCORD_WEBHOOK_URI} 에러났대... https://www.greenart.co.kr/upimage/new_editor/20212/20210201112021.jpg diff --git a/module-api/src/test/java/com/mile/cocurrency/DuplicatedInterceptorTest.java b/module-api/src/test/java/com/mile/cocurrency/DuplicatedInterceptorTest.java index 3b04fbbe..811b0179 100644 --- a/module-api/src/test/java/com/mile/cocurrency/DuplicatedInterceptorTest.java +++ b/module-api/src/test/java/com/mile/cocurrency/DuplicatedInterceptorTest.java @@ -13,9 +13,11 @@ import com.mile.topic.repository.TopicRepository; import com.mile.user.domain.User; import com.mile.user.repository.UserRepository; -import com.mile.utils.SecureUrlUtil; +import com.mile.common.utils.SecureUrlUtil; +import com.mile.writername.domain.MoimRole; import com.mile.writername.domain.WriterName; import com.mile.writername.repository.WriterNameRepository; +import com.mile.writername.service.vo.WriterNameInfo; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.DisplayName; import org.junit.jupiter.api.Test; @@ -29,7 +31,9 @@ import org.springframework.transaction.annotation.Transactional; import java.util.ArrayList; +import java.util.HashMap; import java.util.List; +import java.util.Map; import java.util.UUID; import java.util.concurrent.CountDownLatch; import java.util.concurrent.ExecutorService; @@ -62,6 +66,7 @@ public class DuplicatedInterceptorTest { private static Long USER_ID; private static String MOIM_ID; private static String TOPIC_ID; + private static Map joinedRole = new HashMap<>(); @BeforeEach @Transactional @@ -91,6 +96,7 @@ public void setUp() { MOIM_ID = secureUrlUtil.encodeUrl(moim.getId()); TOPIC_ID = secureUrlUtil.encodeUrl(topic.getId()); + joinedRole.put(moim.getId(), WriterNameInfo.of(writerName.getId(), MoimRole.OWNER)); } @Test @@ -101,7 +107,7 @@ public void multipleRequestTest() throws Exception { int numberOfThread = 4; ExecutorService executorService = Executors.newFixedThreadPool(numberOfThread); CountDownLatch latch = new CountDownLatch(numberOfThread); - String token = "Bearer " + jwtTokenProvider.issueAccessToken(USER_ID); + String token = "Bearer " + jwtTokenProvider.issueAccessToken(USER_ID, joinedRole); PostCreateRequest bodyDto = new PostCreateRequest( MOIM_ID, diff --git a/module-api/src/test/java/com/mile/cocurrency/UniqueNameLockTest.java b/module-api/src/test/java/com/mile/cocurrency/UniqueNameLockTest.java index 65f7efe1..d258dff2 100644 --- a/module-api/src/test/java/com/mile/cocurrency/UniqueNameLockTest.java +++ b/module-api/src/test/java/com/mile/cocurrency/UniqueNameLockTest.java @@ -6,6 +6,7 @@ import com.mile.moim.service.dto.request.MoimCreateRequest; import com.mile.user.domain.User; import com.mile.user.repository.UserRepository; +import com.mile.writername.domain.MoimRole; import org.junit.jupiter.api.DisplayName; import org.junit.jupiter.api.MethodOrderer; import org.junit.jupiter.api.Test; @@ -19,6 +20,7 @@ import org.springframework.test.web.servlet.MvcResult; import java.util.ArrayList; +import java.util.HashMap; import java.util.List; import java.util.UUID; import java.util.concurrent.CountDownLatch; @@ -68,7 +70,7 @@ public void uniqueMoimNameTest() throws Exception { MoimCreateRequest(randomName, "string", false, "string", "string", "string", "string", "str", "string"); String body = objectMapper.writeValueAsString(bodyDto); - String token = "Bearer " + jwtTokenProvider.issueAccessToken(USER_ID); + String token = "Bearer " + jwtTokenProvider.issueAccessToken(USER_ID, new HashMap<>()); // when diff --git a/module-api/src/test/java/com/mile/common/CorsTest.java b/module-api/src/test/java/com/mile/common/CorsTest.java new file mode 100644 index 00000000..fc6d693d --- /dev/null +++ b/module-api/src/test/java/com/mile/common/CorsTest.java @@ -0,0 +1,32 @@ +package com.mile.common; + +import org.junit.jupiter.api.Test; +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.http.MediaType; +import org.springframework.test.web.servlet.MockMvc; + +import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.options; +import static org.springframework.test.web.servlet.result.MockMvcResultHandlers.print; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.header; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; + +@SpringBootTest +@AutoConfigureMockMvc +public class CorsTest { + + @Autowired + private MockMvc mockMvc; + + @Test + public void testCorsWithMockMvc() throws Exception { + mockMvc.perform(options("/api/moim/MQ==") + .header("Origin", "http://localhost:5173") + .header("Access-Control-Request-Method", "OPTIONS") + .header("Access-Control-Request-Headers", "Content-Type") + .accept(MediaType.APPLICATION_JSON)) + .andExpect(status().isOk()) + .andDo(print()); + } +} \ No newline at end of file diff --git a/module-api/src/test/java/com/mile/controller/MoimControllerTest.java b/module-api/src/test/java/com/mile/controller/MoimControllerTest.java index 8fa4745e..5858d423 100644 --- a/module-api/src/test/java/com/mile/controller/MoimControllerTest.java +++ b/module-api/src/test/java/com/mile/controller/MoimControllerTest.java @@ -15,9 +15,11 @@ import com.mile.topic.repository.TopicRepository; import com.mile.user.domain.User; import com.mile.user.repository.UserRepository; -import com.mile.utils.SecureUrlUtil; +import com.mile.common.utils.SecureUrlUtil; +import com.mile.writername.domain.MoimRole; import com.mile.writername.domain.WriterName; import com.mile.writername.repository.WriterNameRepository; +import com.mile.writername.service.vo.WriterNameInfo; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.DisplayName; import org.junit.jupiter.api.Test; @@ -29,6 +31,7 @@ import org.springframework.test.web.servlet.MvcResult; import org.springframework.transaction.annotation.Transactional; +import java.util.HashMap; import java.util.UUID; import static org.assertj.core.api.AssertionsForClassTypes.assertThat; @@ -65,11 +68,12 @@ public class MoimControllerTest { private static final String AUTHORIZATION = "Authorization"; private static final int OK = 200; private static final int CREATED = 201; - private static final int BAD_REQUEST = 400; + private static final int NOT_FOUND = 404; private static Long USER_ID; private static String MOIM_ID; private static String randomString; - + private static HashMap joinedRole = new HashMap<>(); + private static HashMap newJoinedRole = new HashMap<>(); @BeforeEach @Transactional @@ -95,8 +99,9 @@ public void setUp() { moim.setOwner(writerName); moimRepository.saveAndFlush(moim); - Topic topic = topicRepository.saveAndFlush(Topic.create(moim, new TopicCreateRequest(randomString, randomString.substring(0,4), randomString))); + Topic topic = topicRepository.saveAndFlush(Topic.create(moim, new TopicCreateRequest(randomString, randomString.substring(0, 4), randomString))); MOIM_ID = secureUrlUtil.encodeUrl(moim.getId()); + joinedRole.put(moim.getId(), WriterNameInfo.of(writerName.getId(), MoimRole.OWNER)); } /* @@ -123,7 +128,7 @@ public void getBestMoim() throws Exception { public void parameterErrorTest() throws Exception { //given String variable = UUID.randomUUID().toString(); - String requestUri = "/api/moim/" + variable; + String requestUri = "/api/moim/" + variable + "/information"; //when MvcResult result = mockMvc.perform( @@ -132,7 +137,7 @@ public void parameterErrorTest() throws Exception { ).andDo(print()).andReturn(); //then - assertThat(result.getResponse().getStatus()).isEqualTo(BAD_REQUEST); + assertThat(result.getResponse().getStatus()).isEqualTo(NOT_FOUND); } @@ -159,7 +164,7 @@ public void getBestPostOfMoim() throws Exception { @DisplayName("모임 초대 코드가 정상적으로 조회된다.") public void getMoimInvitationCodeTest() throws Exception { //given - String token = "Bearer " + jwtTokenProvider.issueAccessToken(USER_ID); + String token = "Bearer " + jwtTokenProvider.issueAccessToken(USER_ID, joinedRole); String requestUri = "/api/moim/" + MOIM_ID + "/invitation-code"; //when @@ -177,7 +182,7 @@ public void getMoimInvitationCodeTest() throws Exception { @DisplayName("글모임의 주제들이 정상적으로 조회된다.") public void getTopicFromMoimTest() throws Exception { //given - String token = "Bearer " + jwtTokenProvider.issueAccessToken(USER_ID); + String token = "Bearer " + jwtTokenProvider.issueAccessToken(USER_ID, joinedRole); String requestUri = "/api/moim/" + MOIM_ID; //when @@ -196,8 +201,10 @@ public void getTopicFromMoimTest() throws Exception { @DisplayName("글모임에 정상적으로 가입된다.") public void joinMoimTest() throws Exception { //given + randomString = UUID.randomUUID().toString().substring(0, 6); + User user = userRepository.saveAndFlush(User.of(randomString, randomString, SocialType.GOOGLE)); String randomShortString = UUID.randomUUID().toString().substring(0, 6); - String token = "Bearer " + jwtTokenProvider.issueAccessToken(USER_ID); + String token = "Bearer " + jwtTokenProvider.issueAccessToken(user.getId(), newJoinedRole); String requestUri = "/api/moim/" + MOIM_ID + "/user"; String requestBody = objectMapper.writeValueAsString( WriterMemberJoinRequest.of( @@ -216,7 +223,7 @@ public void joinMoimTest() throws Exception { .andReturn(); //then - assertThat(result.getResponse().getStatus()).isEqualTo(CREATED); + assertThat(result.getResponse().getStatus()).isEqualTo(OK); } @Test @@ -275,7 +282,7 @@ public void getPublicStatusTest() throws Exception { public void getTemporaryPostOfMoim() throws Exception { //given String requestUri = "/api/moim/" + MOIM_ID + "/temporary"; - String token = "Bearer " + jwtTokenProvider.issueAccessToken(USER_ID); + String token = "Bearer " + jwtTokenProvider.issueAccessToken(USER_ID, joinedRole); //when MvcResult result = mockMvc.perform( @@ -293,7 +300,7 @@ public void getTemporaryPostOfMoim() throws Exception { @DisplayName("글 모임 뷰의 본인 필명이 정상적으로 반환된다.") public void getWriterNameForUserTest() throws Exception { //given - String token = "Bearer " + jwtTokenProvider.issueAccessToken(USER_ID); + String token = "Bearer " + jwtTokenProvider.issueAccessToken(USER_ID, joinedRole); String requestUri = "/api/moim/" + MOIM_ID + "/writername"; //when @@ -318,7 +325,7 @@ public void postMoimTest() throws Exception { String randomString = UUID.randomUUID().toString().substring(0, 7); String randemTagString = UUID.randomUUID().toString().substring(0, 3); User user = userRepository.save(User.of(randomString, randomString, SocialType.GOOGLE)); - String token = "Bearer " + jwtTokenProvider.issueAccessToken(user.getId()); + String token = "Bearer " + jwtTokenProvider.issueAccessToken(user.getId(), new HashMap<>()); String createRequest = objectMapper.writeValueAsString( new MoimCreateRequest( randomString, @@ -350,7 +357,7 @@ public void postMoimTest() throws Exception { @DisplayName("관리자 페이지 글감 조회가 정상적으로 반환된다.") public void getTopicForOwnerTest() throws Exception { //given - String token = "Bearer " + jwtTokenProvider.issueAccessToken(USER_ID); + String token = "Bearer " + jwtTokenProvider.issueAccessToken(USER_ID, joinedRole); String requestUri = "/api/moim/" + MOIM_ID + "/admin/topics"; @@ -372,7 +379,7 @@ public void getTopicForOwnerTest() throws Exception { @Transactional public void getWriterNamesForOwnerTest() throws Exception { //given - String token = "Bearer " + jwtTokenProvider.issueAccessToken(USER_ID); + String token = "Bearer " + jwtTokenProvider.issueAccessToken(USER_ID, joinedRole); String requestUri = "/api/moim/" + MOIM_ID + "/writernames"; //when @@ -395,7 +402,7 @@ public void putMoimInfoTest() throws Exception { //given String randomTagString = UUID.randomUUID().toString().substring(0, 3); String requestUri = "/api/moim/" + MOIM_ID + "/info"; - String token = "Bearer " + jwtTokenProvider.issueAccessToken(USER_ID); + String token = "Bearer " + jwtTokenProvider.issueAccessToken(USER_ID, joinedRole); String request = objectMapper.writeValueAsString(new MoimInfoModifyRequest( randomString, @@ -420,7 +427,7 @@ public void putMoimInfoTest() throws Exception { @DisplayName("글감을 정상적으로 등록한다.") public void createTopicTest() throws Exception { //given - String token = "Bearer " + jwtTokenProvider.issueAccessToken(USER_ID); + String token = "Bearer " + jwtTokenProvider.issueAccessToken(USER_ID, joinedRole); String requestUri = "/api/moim/" + MOIM_ID + "/topic"; String request = objectMapper.writeValueAsString( TopicCreateRequest.of(randomString, "---", randomString)); @@ -440,7 +447,7 @@ public void createTopicTest() throws Exception { @DisplayName("글모임이 정상적으로 삭제된다.") public void deleteMoimTest() throws Exception { //given - String token = "Bearer " + jwtTokenProvider.issueAccessToken(USER_ID); + String token = "Bearer " + jwtTokenProvider.issueAccessToken(USER_ID, joinedRole); String requestUri = "/api/moim/" + MOIM_ID; //when diff --git a/module-auth/src/main/java/com/mile/jwt/repository/TokenRepository.java b/module-auth/src/main/java/com/mile/jwt/repository/TokenRepository.java index e43d6c6b..92c27b36 100644 --- a/module-auth/src/main/java/com/mile/jwt/repository/TokenRepository.java +++ b/module-auth/src/main/java/com/mile/jwt/repository/TokenRepository.java @@ -9,4 +9,5 @@ public interface TokenRepository extends CrudRepository { Optional findByRefreshToken(final String refreshToken); Optional findById(final Long id); + void deleteById(final long id); } \ No newline at end of file diff --git a/module-auth/src/main/java/com/mile/jwt/service/TokenService.java b/module-auth/src/main/java/com/mile/jwt/service/TokenService.java index cf241df0..4f837570 100644 --- a/module-auth/src/main/java/com/mile/jwt/service/TokenService.java +++ b/module-auth/src/main/java/com/mile/jwt/service/TokenService.java @@ -41,9 +41,6 @@ public Long findIdByRefreshToken( public void deleteRefreshToken( final Long userId ) { - Token token = tokenRepository.findById(userId).orElseThrow( - () -> new NotFoundException(ErrorMessage.REFRESH_TOKEN_NOT_FOUND) - ); - tokenRepository.delete(token); + tokenRepository.deleteById(userId); } } \ No newline at end of file diff --git a/module-common/build.gradle b/module-common/build.gradle index 65671eae..1b210e86 100644 --- a/module-common/build.gradle +++ b/module-common/build.gradle @@ -4,6 +4,4 @@ jar { enabled = true } dependencies { //Aop implementation 'org.springframework.boot:spring-boot-starter-aop' - //Sentry - implementation 'io.sentry:sentry-spring-boot-starter-jakarta:7.9.0' } \ No newline at end of file diff --git a/module-common/src/main/java/com/mile/exception/message/ErrorMessage.java b/module-common/src/main/java/com/mile/exception/message/ErrorMessage.java index a74d3650..02e7f781 100644 --- a/module-common/src/main/java/com/mile/exception/message/ErrorMessage.java +++ b/module-common/src/main/java/com/mile/exception/message/ErrorMessage.java @@ -19,12 +19,9 @@ public enum ErrorMessage { HANDLER_NOT_FOUND(HttpStatus.NOT_FOUND.value(), "요청하신 URL은 정보가 없습니다."), COMMENT_NOT_FOUND(40406, "해당 댓글이 존재하지 않습니다."), CURIOUS_NOT_FOUND(40407, "해당 궁금해요는 존재하지 않습니다."), - TOPIC_NOT_FOUND(40408, "해당 글감이 존재하지 않습니다."), - KEYWORD_NOT_FOUND(40409, "해당 글모임의 글감 키워드가 존재하지 않습니다."), - WRITER_NOT_FOUND(40411, "해당 작가는 존재하지 않습니다."), + TOPIC_NOT_FOUND(40408, "글감이 존재하지 않습니다."), RECOMMEND_NOT_FOUND(40412, "추천 글감을 받아오는데 실패했습니다."), - MOIM_TOPIC_NOT_FOUND(40413, "해당 모임의 글감이 존재하지 않습니다."), - REPLY_NOT_FOUND(40416, "Id에 해당하는 대댓글이 없습니다."), + INVALID_URL_EXCEPTION(40413, "해당 URI는 자원을 표시할 수 없습니다."), /* Bad Request */ @@ -38,11 +35,9 @@ public enum ErrorMessage { BEARER_LOST_ERROR(HttpStatus.BAD_REQUEST.value(), "토큰의 요청에 Bearer이 담겨 있지 않습니다."), POST_NOT_TEMPORARY_ERROR(40008, "해당 글은 임시저장 글이 아닙니다."), POST_TEMPORARY_ERROR(HttpStatus.BAD_REQUEST.value(), "해당 글은 임시저장글입니다."), - PATH_PARAMETER_INVALID_ERROR(40010, "해당 URI는 자원을 표시할 수 없습니다."), REQUEST_URL_WRONG_ERROR(HttpStatus.BAD_REQUEST.value(), "요청 URL를 다시 확인해주세요"), IMAGE_EXTENSION_INVALID_ERROR(HttpStatus.BAD_REQUEST.value(), "이미지 확장자는 jpg, png, webp만 가능합니다."), IMAGE_SIZE_INVALID_ERROR(HttpStatus.BAD_REQUEST.value(), "이미지 사이즈는 5MB를 넘을 수 없습니다."), - INVALID_URL_EXCEPTION(40014, "해당 URI는 자원을 표시할 수 없습니다."), LEAST_TOPIC_SIZE_OF_MOIM_ERROR(40015, "모임에는 최소 하나의 글감이 있어야 합니다."), USER_MOIM_ALREADY_JOIN(40016, "사용자는 이미 모임에 가입했습니다."), WRITER_NAME_LENGTH_WRONG(40017, "사용 불가능한 필명입니다."), diff --git a/module-domain/build.gradle b/module-domain/build.gradle index b8a2e176..151d3be3 100644 --- a/module-domain/build.gradle +++ b/module-domain/build.gradle @@ -11,6 +11,8 @@ dependencies { //Swagger implementation 'org.springdoc:springdoc-openapi-starter-webmvc-ui:2.1.0' + implementation 'org.springframework.boot:spring-boot-starter-cache' + implementation 'com.github.ben-manes.caffeine:caffeine:3.1.2' // QueryDSL Implementation implementation 'com.querydsl:querydsl-jpa:5.0.0:jakarta' diff --git a/module-domain/src/main/java/com/mile/comment/domain/Comment.java b/module-domain/src/main/java/com/mile/comment/domain/Comment.java index 4ea07b00..e1d8272a 100644 --- a/module-domain/src/main/java/com/mile/comment/domain/Comment.java +++ b/module-domain/src/main/java/com/mile/comment/domain/Comment.java @@ -1,6 +1,6 @@ package com.mile.comment.domain; -import com.mile.config.BaseTimeEntity; +import com.mile.common.config.BaseTimeEntity; import com.mile.post.domain.Post; import com.mile.post.service.dto.request.CommentCreateRequest; import com.mile.writername.domain.WriterName; diff --git a/module-domain/src/main/java/com/mile/comment/service/CommentCreator.java b/module-domain/src/main/java/com/mile/comment/service/CommentCreator.java index e0975a3d..3d4ca3fa 100644 --- a/module-domain/src/main/java/com/mile/comment/service/CommentCreator.java +++ b/module-domain/src/main/java/com/mile/comment/service/CommentCreator.java @@ -4,7 +4,7 @@ import com.mile.comment.repository.CommentRepository; import com.mile.post.domain.Post; import com.mile.post.service.dto.request.CommentCreateRequest; -import com.mile.utils.SecureUrlUtil; +import com.mile.common.utils.SecureUrlUtil; import com.mile.writername.domain.WriterName; import lombok.RequiredArgsConstructor; import org.springframework.stereotype.Component; diff --git a/module-domain/src/main/java/com/mile/comment/service/CommentService.java b/module-domain/src/main/java/com/mile/comment/service/CommentService.java index ea957cb1..f6fbc06d 100644 --- a/module-domain/src/main/java/com/mile/comment/service/CommentService.java +++ b/module-domain/src/main/java/com/mile/comment/service/CommentService.java @@ -54,13 +54,10 @@ public void deleteReply( } public List getCommentResponse( - final Long moimId, final Post post, - final Long userId + final Long writerNameId ) { - postRetriever.authenticateUserWithPost(post, userId); List commentList = commentRetriever.findByPostId(post.getId()); - Long writerNameId = writerNameRetriever.getWriterNameIdByMoimIdAndUserId(moimId, userId); return commentList.stream() .map(comment -> CommentResponse.of( diff --git a/module-domain/src/main/java/com/mile/commentreply/service/CommentReplyCreator.java b/module-domain/src/main/java/com/mile/commentreply/service/CommentReplyCreator.java index cb6141a7..bacb805a 100644 --- a/module-domain/src/main/java/com/mile/commentreply/service/CommentReplyCreator.java +++ b/module-domain/src/main/java/com/mile/commentreply/service/CommentReplyCreator.java @@ -4,7 +4,7 @@ import com.mile.commentreply.domain.CommentReply; import com.mile.commentreply.repository.CommentReplyRepository; import com.mile.commentreply.service.dto.request.ReplyCreateRequest; -import com.mile.utils.SecureUrlUtil; +import com.mile.common.utils.SecureUrlUtil; import com.mile.writername.domain.WriterName; import lombok.RequiredArgsConstructor; import org.springframework.stereotype.Component; diff --git a/module-domain/src/main/java/com/mile/commentreply/service/CommentReplyRetriever.java b/module-domain/src/main/java/com/mile/commentreply/service/CommentReplyRetriever.java index b2162935..c9fde482 100644 --- a/module-domain/src/main/java/com/mile/commentreply/service/CommentReplyRetriever.java +++ b/module-domain/src/main/java/com/mile/commentreply/service/CommentReplyRetriever.java @@ -26,7 +26,7 @@ public CommentReply findById( final Long replyId ) { return commentReplyRepository.findById(replyId).orElseThrow( - () -> new NotFoundException(ErrorMessage.REPLY_NOT_FOUND) + () -> new NotFoundException(ErrorMessage.COMMENT_NOT_FOUND) ); } diff --git a/module-domain/src/main/java/com/mile/config/BaseTimeEntity.java b/module-domain/src/main/java/com/mile/common/config/BaseTimeEntity.java similarity index 94% rename from module-domain/src/main/java/com/mile/config/BaseTimeEntity.java rename to module-domain/src/main/java/com/mile/common/config/BaseTimeEntity.java index f80bb216..e094492a 100644 --- a/module-domain/src/main/java/com/mile/config/BaseTimeEntity.java +++ b/module-domain/src/main/java/com/mile/common/config/BaseTimeEntity.java @@ -1,4 +1,4 @@ -package com.mile.config; +package com.mile.common.config; import jakarta.persistence.EntityListeners; import jakarta.persistence.MappedSuperclass; diff --git a/module-domain/src/main/java/com/mile/common/config/CacheConfig.java b/module-domain/src/main/java/com/mile/common/config/CacheConfig.java new file mode 100644 index 00000000..32e8ab0d --- /dev/null +++ b/module-domain/src/main/java/com/mile/common/config/CacheConfig.java @@ -0,0 +1,38 @@ +package com.mile.common.config; + +import com.github.benmanes.caffeine.cache.Caffeine; +import com.github.benmanes.caffeine.cache.Scheduler; +import org.springframework.cache.CacheManager; +import org.springframework.cache.annotation.EnableCaching; +import org.springframework.cache.caffeine.CaffeineCacheManager; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; + +import java.util.concurrent.Executors; +import java.util.concurrent.ScheduledExecutorService; +import java.util.concurrent.TimeUnit; + +@Configuration +@EnableCaching +public class CacheConfig { + @Bean + public CacheManager cacheManager() { + CaffeineCacheManager cacheManager = new CaffeineCacheManager(); + cacheManager.setCaffeine(caffeineConfig()); + return cacheManager; + } + + private Scheduler getScheduler() { + ScheduledExecutorService executor = Executors.newScheduledThreadPool(5); + Scheduler scheduler; + scheduler = Scheduler.forScheduledExecutorService(executor); + return scheduler; + } + + private Caffeine caffeineConfig() { + return Caffeine.newBuilder() + .maximumSize(200) + .expireAfterAccess(5, TimeUnit.DAYS) + .scheduler(getScheduler()); + } +} diff --git a/module-domain/src/main/java/com/mile/config/JpaAuditingConfig.java b/module-domain/src/main/java/com/mile/common/config/JpaAuditingConfig.java similarity index 86% rename from module-domain/src/main/java/com/mile/config/JpaAuditingConfig.java rename to module-domain/src/main/java/com/mile/common/config/JpaAuditingConfig.java index 95956417..0c6f87d8 100644 --- a/module-domain/src/main/java/com/mile/config/JpaAuditingConfig.java +++ b/module-domain/src/main/java/com/mile/common/config/JpaAuditingConfig.java @@ -1,4 +1,4 @@ -package com.mile.config; +package com.mile.common.config; import org.springframework.context.annotation.Configuration; import org.springframework.data.jpa.repository.config.EnableJpaAuditing; diff --git a/module-domain/src/main/java/com/mile/config/querydsl/QueryDslConfig.java b/module-domain/src/main/java/com/mile/common/config/querydsl/QueryDslConfig.java similarity index 92% rename from module-domain/src/main/java/com/mile/config/querydsl/QueryDslConfig.java rename to module-domain/src/main/java/com/mile/common/config/querydsl/QueryDslConfig.java index c594ed7b..97492e14 100644 --- a/module-domain/src/main/java/com/mile/config/querydsl/QueryDslConfig.java +++ b/module-domain/src/main/java/com/mile/common/config/querydsl/QueryDslConfig.java @@ -1,4 +1,4 @@ -package com.mile.config.querydsl; +package com.mile.common.config.querydsl; import com.querydsl.jpa.impl.JPAQueryFactory; import jakarta.persistence.EntityManager; diff --git a/module-domain/src/main/java/com/mile/utils/DateUtil.java b/module-domain/src/main/java/com/mile/common/utils/DateUtil.java similarity index 99% rename from module-domain/src/main/java/com/mile/utils/DateUtil.java rename to module-domain/src/main/java/com/mile/common/utils/DateUtil.java index 5a5090c1..a5bc1f74 100644 --- a/module-domain/src/main/java/com/mile/utils/DateUtil.java +++ b/module-domain/src/main/java/com/mile/common/utils/DateUtil.java @@ -1,4 +1,4 @@ -package com.mile.utils; +package com.mile.common.utils; import org.springframework.stereotype.Component; diff --git a/module-domain/src/main/java/com/mile/utils/JsoupUtil.java b/module-domain/src/main/java/com/mile/common/utils/JsoupUtil.java similarity index 93% rename from module-domain/src/main/java/com/mile/utils/JsoupUtil.java rename to module-domain/src/main/java/com/mile/common/utils/JsoupUtil.java index ef2a9939..595b67cd 100644 --- a/module-domain/src/main/java/com/mile/utils/JsoupUtil.java +++ b/module-domain/src/main/java/com/mile/common/utils/JsoupUtil.java @@ -1,4 +1,4 @@ -package com.mile.utils; +package com.mile.common.utils; import org.jsoup.Jsoup; import org.jsoup.nodes.Document; diff --git a/module-domain/src/main/java/com/mile/utils/SecureUrlUtil.java b/module-domain/src/main/java/com/mile/common/utils/SecureUrlUtil.java similarity index 80% rename from module-domain/src/main/java/com/mile/utils/SecureUrlUtil.java rename to module-domain/src/main/java/com/mile/common/utils/SecureUrlUtil.java index 5ad60d8b..a6fe6c12 100644 --- a/module-domain/src/main/java/com/mile/utils/SecureUrlUtil.java +++ b/module-domain/src/main/java/com/mile/common/utils/SecureUrlUtil.java @@ -1,7 +1,8 @@ -package com.mile.utils; +package com.mile.common.utils; import com.mile.exception.message.ErrorMessage; import com.mile.exception.model.BadRequestException; +import com.mile.exception.model.NotFoundException; import org.springframework.stereotype.Component; import java.util.Base64; @@ -17,7 +18,7 @@ public Long decodeUrl(final String url) { try { return Long.parseLong(new String(Base64.getUrlDecoder().decode(url))); } catch (IllegalArgumentException e) { - throw new BadRequestException(ErrorMessage.PATH_PARAMETER_INVALID_ERROR); + throw new NotFoundException(ErrorMessage.INVALID_URL_EXCEPTION); } } diff --git a/module-domain/src/main/java/com/mile/curious/domain/Curious.java b/module-domain/src/main/java/com/mile/curious/domain/Curious.java index 80836606..85394f79 100644 --- a/module-domain/src/main/java/com/mile/curious/domain/Curious.java +++ b/module-domain/src/main/java/com/mile/curious/domain/Curious.java @@ -1,6 +1,6 @@ package com.mile.curious.domain; -import com.mile.config.BaseTimeEntity; +import com.mile.common.config.BaseTimeEntity; import com.mile.post.domain.Post; import com.mile.writername.domain.WriterName; import jakarta.persistence.Entity; diff --git a/module-domain/src/main/java/com/mile/curious/repository/CuriousRepository.java b/module-domain/src/main/java/com/mile/curious/repository/CuriousRepository.java index ef9be3aa..1481a9a1 100644 --- a/module-domain/src/main/java/com/mile/curious/repository/CuriousRepository.java +++ b/module-domain/src/main/java/com/mile/curious/repository/CuriousRepository.java @@ -1,9 +1,7 @@ package com.mile.curious.repository; + import com.mile.curious.domain.Curious; import com.mile.post.domain.Post; -import com.mile.user.domain.User; -import java.util.List; - import com.mile.writername.domain.WriterName; import org.springframework.data.jpa.repository.JpaRepository; import org.springframework.data.jpa.repository.Modifying; @@ -11,8 +9,11 @@ import org.springframework.data.repository.query.Param; import org.springframework.transaction.annotation.Transactional; -public interface CuriousRepository extends JpaRepository { +import java.util.List; + +public interface CuriousRepository extends JpaRepository, CuriousRepositoryCustom { boolean existsByPostAndWriterName(final Post post, final WriterName writerName); + Curious findByPostAndWriterName(final Post post, final WriterName writerName); @Transactional diff --git a/module-domain/src/main/java/com/mile/curious/repository/CuriousRepositoryCustom.java b/module-domain/src/main/java/com/mile/curious/repository/CuriousRepositoryCustom.java new file mode 100644 index 00000000..e0e34d9d --- /dev/null +++ b/module-domain/src/main/java/com/mile/curious/repository/CuriousRepositoryCustom.java @@ -0,0 +1,13 @@ +package com.mile.curious.repository; + +import com.mile.curious.repository.dto.PostAndCuriousCountInLastWeek; +import com.mile.moim.domain.Moim; +import com.mile.post.domain.Post; + +import java.time.LocalDateTime; +import java.util.List; + +public interface CuriousRepositoryCustom { + List findMostCuriousPostBeforeOneWeek(final Moim moim, final LocalDateTime now); + List findPostByLatestCurious(final Moim moim, final int requestSize, final List posts); +} diff --git a/module-domain/src/main/java/com/mile/curious/repository/CuriousRepositoryCustomImpl.java b/module-domain/src/main/java/com/mile/curious/repository/CuriousRepositoryCustomImpl.java new file mode 100644 index 00000000..fbe05dee --- /dev/null +++ b/module-domain/src/main/java/com/mile/curious/repository/CuriousRepositoryCustomImpl.java @@ -0,0 +1,47 @@ +package com.mile.curious.repository; + +import com.mile.curious.repository.dto.PostAndCuriousCountInLastWeek; +import com.mile.moim.domain.Moim; +import com.mile.post.domain.Post; +import com.querydsl.core.types.Projections; +import com.querydsl.jpa.impl.JPAQueryFactory; +import lombok.RequiredArgsConstructor; + +import static com.mile.curious.domain.QCurious.curious; +import static com.mile.post.domain.QPost.post; +import static com.mile.moim.domain.QMoim.moim; +import static com.mile.topic.domain.QTopic.topic; + +import java.time.LocalDateTime; +import java.util.List; + +@RequiredArgsConstructor +public class CuriousRepositoryCustomImpl implements CuriousRepositoryCustom { + + private final JPAQueryFactory queryFactory; + + @Override + public List findMostCuriousPostBeforeOneWeek(final Moim targetMoim, final LocalDateTime now) { + final long WEEK = 7L; + return queryFactory.select(Projections.constructor(PostAndCuriousCountInLastWeek.class, post, curious.count().as("count"))) + .from(curious) + .join(curious.post, post) + .join(topic).on(post.topic.id.eq(topic.id)) + .join(moim).on(topic.moim.id.eq(moim.id)) + .where(moim.id.eq(targetMoim.getId())) + .where(curious.createdAt.between(now.minusDays(WEEK), now)) + .groupBy(post.id) + .fetch(); + } + + @Override + public List findPostByLatestCurious(final Moim moim, final int requestSize, final List posts) { + return queryFactory.select(post) + .from(curious) + .join(curious.post, post) + .where(post.notIn(posts)) + .orderBy(curious.createdAt.desc()) + .limit(requestSize) + .fetch(); + } +} diff --git a/module-domain/src/main/java/com/mile/curious/repository/dto/PostAndCuriousCountInLastWeek.java b/module-domain/src/main/java/com/mile/curious/repository/dto/PostAndCuriousCountInLastWeek.java new file mode 100644 index 00000000..efe453ea --- /dev/null +++ b/module-domain/src/main/java/com/mile/curious/repository/dto/PostAndCuriousCountInLastWeek.java @@ -0,0 +1,19 @@ +package com.mile.curious.repository.dto; + +import com.mile.post.domain.Post; +import lombok.AllArgsConstructor; +import lombok.Getter; +import lombok.Setter; + +@Getter +@Setter +@AllArgsConstructor +public class PostAndCuriousCountInLastWeek implements Comparable { + private Post post; + private Long count; + + @Override + public int compareTo(final PostAndCuriousCountInLastWeek target) { + return Long.compare(this.count, target.count); + } +} diff --git a/module-domain/src/main/java/com/mile/curious/service/CuriousRetriever.java b/module-domain/src/main/java/com/mile/curious/service/CuriousRetriever.java index 6b340f49..f400cc1d 100644 --- a/module-domain/src/main/java/com/mile/curious/service/CuriousRetriever.java +++ b/module-domain/src/main/java/com/mile/curious/service/CuriousRetriever.java @@ -2,16 +2,21 @@ import com.mile.curious.domain.Curious; import com.mile.curious.repository.CuriousRepository; +import com.mile.curious.repository.dto.PostAndCuriousCountInLastWeek; import com.mile.exception.message.ErrorMessage; import com.mile.exception.model.ConflictException; import com.mile.exception.model.NotFoundException; +import com.mile.moim.domain.Moim; import com.mile.post.domain.Post; import com.mile.writername.domain.WriterName; import lombok.AccessLevel; import lombok.RequiredArgsConstructor; import org.springframework.stereotype.Component; +import java.time.LocalDateTime; +import java.util.Collections; import java.util.List; +import java.util.stream.Collectors; @Component @RequiredArgsConstructor(access = AccessLevel.PRIVATE) @@ -38,4 +43,18 @@ public void checkCuriousNotExists(final Post post, final WriterName writerName) public boolean findCuriousExists(final Post post, final WriterName writerName) { return curiousRepository.existsByPostAndWriterName(post, writerName); } + + public List findMostCuriousPostsInLastWeek(final Moim moim) { + List mostCuriousPostsInLastWeek = curiousRepository.findMostCuriousPostBeforeOneWeek(moim, LocalDateTime.now()).stream() + .filter(p -> p.getCount() > 0) + .sorted(Collections.reverseOrder()).collect(Collectors.toList()); + if (mostCuriousPostsInLastWeek.size() < 2) { + List existingPost = mostCuriousPostsInLastWeek.stream().map(PostAndCuriousCountInLastWeek::getPost).toList(); + mostCuriousPostsInLastWeek.addAll( + curiousRepository.findPostByLatestCurious(moim, 2 - mostCuriousPostsInLastWeek.size(), existingPost) + .stream().map(p -> new PostAndCuriousCountInLastWeek(p, 0L)).toList() + ); + } + return mostCuriousPostsInLastWeek; + } } diff --git a/module-domain/src/main/java/com/mile/curious/service/CuriousService.java b/module-domain/src/main/java/com/mile/curious/service/CuriousService.java index 064c882f..a6c66f8a 100644 --- a/module-domain/src/main/java/com/mile/curious/service/CuriousService.java +++ b/module-domain/src/main/java/com/mile/curious/service/CuriousService.java @@ -22,14 +22,14 @@ public void deleteCurious(final Post post, final WriterName writerName) { curiousRetriever.checkCuriousNotExists(post, writerName); curiousRemover.deleteCurious(post, writerName); post.decreaseCuriousCount(); - writerNameUpdator.decreaseTotalCuriousCountByWriterName(writerName); + writerNameUpdator.decreaseTotalCuriousCountByWriterName(post.getWriterName()); } public void createCurious(final Post post, final WriterName writerName) { curiousRetriever.checkCuriousExists(post, writerName); curiousCreator.createCurious(post, writerName); post.increaseCuriousCount(); - writerNameUpdator.increaseTotalCuriousCountByWriterName(writerName); + writerNameUpdator.increaseTotalCuriousCountByWriterName(post.getWriterName()); } diff --git a/module-domain/src/main/java/com/mile/moim/domain/Moim.java b/module-domain/src/main/java/com/mile/moim/domain/Moim.java index 2dea1ab8..47a27555 100644 --- a/module-domain/src/main/java/com/mile/moim/domain/Moim.java +++ b/module-domain/src/main/java/com/mile/moim/domain/Moim.java @@ -1,6 +1,6 @@ package com.mile.moim.domain; -import com.mile.config.BaseTimeEntity; +import com.mile.common.config.BaseTimeEntity; import com.mile.moim.service.dto.request.MoimCreateRequest; import com.mile.moim.service.dto.request.MoimInfoModifyRequest; import com.mile.writername.domain.WriterName; diff --git a/module-domain/src/main/java/com/mile/moim/domain/popular/MoimCuriousPost.java b/module-domain/src/main/java/com/mile/moim/domain/popular/MoimCuriousPost.java new file mode 100644 index 00000000..f8ab8d24 --- /dev/null +++ b/module-domain/src/main/java/com/mile/moim/domain/popular/MoimCuriousPost.java @@ -0,0 +1,31 @@ +package com.mile.moim.domain.popular; + +import com.mile.post.domain.Post; +import jakarta.persistence.Embeddable; +import lombok.AccessLevel; +import lombok.AllArgsConstructor; +import lombok.Getter; +import lombok.NoArgsConstructor; + +@Embeddable +@Getter +@NoArgsConstructor(access = AccessLevel.PROTECTED) +@AllArgsConstructor(access = AccessLevel.PRIVATE) +public class MoimCuriousPost { + private String title; + private String idUrl; + private String contents; + private String imgUrl; + private String topic; + private boolean isContainPhoto; + public static MoimCuriousPost of(final Post post) { + return new MoimCuriousPost( + post.getTitle(), + post.getIdUrl(), + post.getContent(), + post.getImageUrl(), + post.getTopic().getContent(), + post.isContainPhoto() + ); + } +} diff --git a/module-domain/src/main/java/com/mile/moim/domain/popular/MoimCuriousWriter.java b/module-domain/src/main/java/com/mile/moim/domain/popular/MoimCuriousWriter.java new file mode 100644 index 00000000..ca9c3a8e --- /dev/null +++ b/module-domain/src/main/java/com/mile/moim/domain/popular/MoimCuriousWriter.java @@ -0,0 +1,22 @@ +package com.mile.moim.domain.popular; + +import com.mile.writername.domain.WriterName; +import jakarta.persistence.Embeddable; +import lombok.AccessLevel; +import lombok.Getter; +import lombok.NoArgsConstructor; + +@Embeddable +@Getter +@NoArgsConstructor(access = AccessLevel.PROTECTED) +public class MoimCuriousWriter { + String name; + + private MoimCuriousWriter(final String name) { + this.name = name; + } + + public static MoimCuriousWriter of(final WriterName writerName) { + return new MoimCuriousWriter(writerName.getName()); + } +} diff --git a/module-domain/src/main/java/com/mile/moim/domain/popular/MoimPopularInfo.java b/module-domain/src/main/java/com/mile/moim/domain/popular/MoimPopularInfo.java new file mode 100644 index 00000000..03adf70d --- /dev/null +++ b/module-domain/src/main/java/com/mile/moim/domain/popular/MoimPopularInfo.java @@ -0,0 +1,43 @@ +package com.mile.moim.domain.popular; + +import jakarta.persistence.Column; +import jakarta.persistence.ElementCollection; +import jakarta.persistence.Entity; +import jakarta.persistence.FetchType; +import jakarta.persistence.GeneratedValue; +import jakarta.persistence.GenerationType; +import jakarta.persistence.Id; +import lombok.AccessLevel; +import lombok.Getter; +import lombok.NoArgsConstructor; + +import java.util.List; + +@Entity +@Getter +@NoArgsConstructor(access = AccessLevel.PROTECTED) +public class MoimPopularInfo { + + @Id + @GeneratedValue(strategy = GenerationType.IDENTITY) + private Long id; + + @Column(nullable = false, name = "moim_id") + private Long moimId; + + @ElementCollection(fetch = FetchType.EAGER) + private List posts; + + @ElementCollection(fetch = FetchType.EAGER) + private List writers; + + private MoimPopularInfo(final Long moimId, final List posts, final List writers) { + this.moimId = moimId; + this.posts = posts; + this.writers = writers; + } + + public static MoimPopularInfo of(final Long moimId, final List posts, final List writers) { + return new MoimPopularInfo(moimId, posts, writers); + } +} diff --git a/module-domain/src/main/java/com/mile/moim/repository/MoimPopularInfoRepository.java b/module-domain/src/main/java/com/mile/moim/repository/MoimPopularInfoRepository.java new file mode 100644 index 00000000..64808e95 --- /dev/null +++ b/module-domain/src/main/java/com/mile/moim/repository/MoimPopularInfoRepository.java @@ -0,0 +1,17 @@ +package com.mile.moim.repository; + +import com.mile.moim.domain.popular.MoimPopularInfo; +import org.springframework.data.repository.Repository; +import org.springframework.scheduling.annotation.Scheduled; + +import java.util.Optional; + +public interface MoimPopularInfoRepository extends Repository { + + Optional findByMoimId(final long moimId); + + MoimPopularInfo save(final MoimPopularInfo moimPopularInfo); + + @Scheduled(cron = "59 59 23 * * SUN") + void deleteAll(); +} diff --git a/module-domain/src/main/java/com/mile/moim/service/MoimRetriever.java b/module-domain/src/main/java/com/mile/moim/service/MoimRetriever.java index 18ace9d9..f5b3be0f 100644 --- a/module-domain/src/main/java/com/mile/moim/service/MoimRetriever.java +++ b/module-domain/src/main/java/com/mile/moim/service/MoimRetriever.java @@ -5,8 +5,10 @@ import com.mile.exception.model.NotFoundException; import com.mile.moim.domain.Moim; import com.mile.moim.repository.MoimRepository; +import com.mile.moim.service.dto.response.MoimInfoResponse; import com.mile.moim.service.lock.AtomicValidateUniqueMoimName; import com.mile.user.domain.User; +import com.mile.common.utils.DateUtil; import com.mile.writername.domain.WriterName; import lombok.RequiredArgsConstructor; import org.springframework.data.domain.PageRequest; @@ -30,6 +32,19 @@ public Moim findById( () -> new NotFoundException(ErrorMessage.MOIM_NOT_FOUND) ); } + public MoimInfoResponse getMoimInfoForTotal( + final Moim moim, + final int numberOfWriters + ) { + return MoimInfoResponse.of( + moim.getImageUrl(), + moim.getName(), + moim.getOwner().getName(), + moim.getInformation(), + numberOfWriters, + DateUtil.getStringDateOfLocalDate(moim.getCreatedAt()) + ); + } public void authenticateOwnerOfMoim( final Moim moim, diff --git a/module-domain/src/main/java/com/mile/moim/service/MoimService.java b/module-domain/src/main/java/com/mile/moim/service/MoimService.java index 16c1f390..e82c9b68 100644 --- a/module-domain/src/main/java/com/mile/moim/service/MoimService.java +++ b/module-domain/src/main/java/com/mile/moim/service/MoimService.java @@ -1,32 +1,41 @@ package com.mile.moim.service; +import com.mile.common.utils.DateUtil; +import com.mile.common.utils.SecureUrlUtil; +import com.mile.curious.service.CuriousRetriever; import com.mile.exception.message.ErrorMessage; import com.mile.exception.model.BadRequestException; import com.mile.exception.model.ForbiddenException; import com.mile.moim.domain.Moim; +import com.mile.moim.domain.popular.MoimCuriousWriter; +import com.mile.moim.domain.popular.MoimPopularInfo; +import com.mile.moim.service.dto.MoimIdValueDto; +import com.mile.moim.service.dto.request.MoimCreateRequest; +import com.mile.moim.service.dto.request.MoimInfoModifyRequest; +import com.mile.moim.service.dto.request.TopicCreateRequest; +import com.mile.moim.service.dto.request.WriterMemberJoinRequest; import com.mile.moim.service.dto.response.BestMoimListResponse; import com.mile.moim.service.dto.response.ContentListResponse; import com.mile.moim.service.dto.response.InvitationCodeGetResponse; import com.mile.moim.service.dto.response.MoimAuthenticateResponse; -import com.mile.moim.service.dto.request.MoimCreateRequest; import com.mile.moim.service.dto.response.MoimCreateResponse; import com.mile.moim.service.dto.response.MoimCuriousPostListResponse; -import com.mile.moim.service.dto.request.MoimInfoModifyRequest; import com.mile.moim.service.dto.response.MoimInfoOwnerResponse; import com.mile.moim.service.dto.response.MoimInfoResponse; import com.mile.moim.service.dto.response.MoimInvitationInfoResponse; +import com.mile.moim.service.dto.response.MoimMostCuriousPostResponse; +import com.mile.moim.service.dto.response.MoimMostCuriousWriterResponse; import com.mile.moim.service.dto.response.MoimNameConflictCheckResponse; +import com.mile.moim.service.dto.response.MoimOverallInfoResponse; import com.mile.moim.service.dto.response.MoimPublicStatusResponse; import com.mile.moim.service.dto.response.MoimTopicInfoListResponse; import com.mile.moim.service.dto.response.MoimTopicResponse; import com.mile.moim.service.dto.response.MoimWriterNameListGetResponse; -import com.mile.moim.service.dto.response.PopularWriterListResponse; import com.mile.moim.service.dto.response.TemporaryPostExistResponse; -import com.mile.moim.service.dto.request.TopicCreateRequest; import com.mile.moim.service.dto.response.TopicListResponse; -import com.mile.moim.service.dto.request.WriterMemberJoinRequest; import com.mile.moim.service.dto.response.WriterNameConflictCheckResponse; import com.mile.moim.service.lock.AtomicValidateUniqueMoimName; +import com.mile.moim.service.popular.MoimPopularInfoService; import com.mile.post.domain.Post; import com.mile.post.service.PostRetriever; import com.mile.topic.service.TopicCreator; @@ -34,13 +43,11 @@ import com.mile.topic.service.TopicRetriever; import com.mile.user.domain.User; import com.mile.user.service.UserRetriever; -import com.mile.utils.DateUtil; -import com.mile.utils.SecureUrlUtil; import com.mile.writername.domain.WriterName; import com.mile.writername.service.WriterNameRemover; import com.mile.writername.service.WriterNameRetriever; import com.mile.writername.service.WriterNameService; -import com.mile.writername.service.dto.response.WriterNameShortResponse; +import com.mile.writername.service.dto.response.WriterNameInformationResponse; import lombok.RequiredArgsConstructor; import org.springframework.stereotype.Service; @@ -61,28 +68,26 @@ public class MoimService { private final MoimRetriever moimRetriever; private final MoimCreator moimCreator; private final WriterNameRemover writerNameRemover; - + private final CuriousRetriever curiousRetriever; private final TopicRemover topicRemover; private final TopicRetriever topicRetriever; private final TopicCreator topicCreator; + private final MoimPopularInfoService moimPopularInfoService; private static final int WRITER_NAME_MAX_VALUE = 8; private static final int MOIM_NAME_MAX_VALUE = 10; private static final int BEST_MOIM_DEFAULT_NUMBER = 3; public ContentListResponse getContentsFromMoim( - final Long moimId, - final Long userId + final Long moimId ) { - postRetriever.authenticateUserOfMoim(writerNameRetriever.isUserInMoim(moimId, userId)); return ContentListResponse.of(topicRetriever.getContentsFromMoim(moimId)); } - public WriterNameShortResponse getWriterNameOfUser( - final Long moimId, - final Long userId + public WriterNameInformationResponse getWriterNameOfUser( + final Long writerNameId ) { - return writerNameRetriever.findWriterNameInfo(moimId, userId); + return writerNameRetriever.findWriterNameInfo(writerNameId); } public WriterNameConflictCheckResponse checkConflictOfWriterName(Long moimId, String writerName) { @@ -125,11 +130,13 @@ public MoimAuthenticateResponse getAuthenticateUserOfMoim( return MoimAuthenticateResponse.of(writerNameRetriever.isUserInMoim(moimId, userId), moimRetriever.isMoimOwnerEqualsUser(moimRetriever.findById(moimId), userId)); } - public PopularWriterListResponse getMostCuriousWritersOfMoim( + public MoimMostCuriousWriterResponse getMostCuriousWritersOfMoim( final Long moimId ) { - List writers = writerNameRetriever.findTop2ByCuriousCount(moimId); - return PopularWriterListResponse.of(writers); + Moim moim = moimRetriever.findById(moimId); + List writers = writerNameRetriever.findTop2ByCuriousCount(moim); + List curiousWriters = writers.stream().map(MoimCuriousWriter::of).toList(); + return MoimMostCuriousWriterResponse.of(curiousWriters); } @@ -153,8 +160,21 @@ public MoimInfoResponse getMoimInfo( ); } + + public MoimOverallInfoResponse getMoimTotalInformation(final Long moimId) { + Moim moim = moimRetriever.findById(moimId); + MoimInfoResponse moimInfoResponse = moimRetriever.getMoimInfoForTotal(moim, writerNameRetriever.findNumbersOfWritersByMoim(moim)); + MoimPopularInfo moimPopularInfo = moimPopularInfoService.getMoimPopularInfo(moim); + MoimMostCuriousWriterResponse mostCuriousWriterResponse = MoimMostCuriousWriterResponse.of(moimPopularInfo.getWriters()); + MoimCuriousPostListResponse moimCuriousPostListResponse = MoimCuriousPostListResponse.of( + moimPopularInfo.getPosts().stream().map(MoimMostCuriousPostResponse::of).toList() + ); + return new MoimOverallInfoResponse(moimInfoResponse, moimCuriousPostListResponse, mostCuriousWriterResponse); + } + public MoimCuriousPostListResponse getMostCuriousPostFromMoim(final Long moimId) { - return postRetriever.getMostCuriousPostByMoim(moimRetriever.findById(moimId)); + Moim moim = moimRetriever.findById(moimId); + return postRetriever.getMostCuriousPostByMoim(moim); } public TopicListResponse getTopicList( @@ -276,7 +296,7 @@ public String createTopic( } @AtomicValidateUniqueMoimName - public MoimCreateResponse createMoim( + public MoimIdValueDto createMoim( final Long userId, final MoimCreateRequest createRequest ) { @@ -284,13 +304,13 @@ public MoimCreateResponse createMoim( Moim moim = moimCreator.createMoim(createRequest); User user = userRetriever.findById(userId); - setMoimOwner(moim, user, createRequest); + final Long writerNameId = setMoimOwner(moim, user, createRequest); setFirstTopic(moim, userId, createRequest); - return MoimCreateResponse.of(moim.getIdUrl(), moim.getIdUrl()); + return MoimIdValueDto.of(moim.getId(), writerNameId, MoimCreateResponse.of(moim.getIdUrl(), moim.getIdUrl())); } - private void setMoimOwner( + private Long setMoimOwner( final Moim moim, final User user, final MoimCreateRequest createRequest @@ -299,6 +319,7 @@ private void setMoimOwner( WriterName owner = writerNameRetriever.findById(writerNameService.createWriterName(user, moim, joinRequest)); moim.setOwner(owner); moim.setIdUrl(secureUrlUtil.encodeUrl(moim.getId())); + return owner.getId(); } @@ -313,11 +334,9 @@ private void setFirstTopic( } public MoimInfoOwnerResponse getMoimInfoForOwner( - final Long moimId, - final Long userId + final Long moimId ) { Moim moim = moimRetriever.findById(moimId); - moimRetriever.authenticateOwnerOfMoim(moim, userRetriever.findById(userId)); return MoimInfoOwnerResponse.of(moim); } diff --git a/module-domain/src/main/java/com/mile/moim/service/dto/MoimIdValueDto.java b/module-domain/src/main/java/com/mile/moim/service/dto/MoimIdValueDto.java new file mode 100644 index 00000000..f1fade00 --- /dev/null +++ b/module-domain/src/main/java/com/mile/moim/service/dto/MoimIdValueDto.java @@ -0,0 +1,15 @@ +package com.mile.moim.service.dto; + +public record MoimIdValueDto( + Long moimId, + Long writerNameId, + T data +) { + public static MoimIdValueDto of( + final Long moimId, + final Long writerNameId, + final T data + ) { + return new MoimIdValueDto<>(moimId, writerNameId, data); + } +} diff --git a/module-domain/src/main/java/com/mile/moim/service/dto/response/BestMoimPostResponse.java b/module-domain/src/main/java/com/mile/moim/service/dto/response/BestMoimPostResponse.java index f0996e22..d768d471 100644 --- a/module-domain/src/main/java/com/mile/moim/service/dto/response/BestMoimPostResponse.java +++ b/module-domain/src/main/java/com/mile/moim/service/dto/response/BestMoimPostResponse.java @@ -1,7 +1,7 @@ package com.mile.moim.service.dto.response; import com.mile.post.domain.Post; -import com.mile.utils.JsoupUtil; +import com.mile.common.utils.JsoupUtil; public record BestMoimPostResponse(String postId, String topicName, String imageUrl, String postTitle, String postContent, Boolean isContainPhoto) { diff --git a/module-domain/src/main/java/com/mile/moim/service/dto/response/MoimCreateResponse.java b/module-domain/src/main/java/com/mile/moim/service/dto/response/MoimCreateResponse.java index 5fc3746b..5214c6b8 100644 --- a/module-domain/src/main/java/com/mile/moim/service/dto/response/MoimCreateResponse.java +++ b/module-domain/src/main/java/com/mile/moim/service/dto/response/MoimCreateResponse.java @@ -5,9 +5,10 @@ public record MoimCreateResponse( String inviteCode ) { public static MoimCreateResponse of( - String moimId, - String inviteCode + final String moimId, + final String inviteCode ) { return new MoimCreateResponse(moimId, inviteCode); } + } diff --git a/module-domain/src/main/java/com/mile/moim/service/dto/response/MoimInvitationInfoResponse.java b/module-domain/src/main/java/com/mile/moim/service/dto/response/MoimInvitationInfoResponse.java index dbe1de87..813f7df5 100644 --- a/module-domain/src/main/java/com/mile/moim/service/dto/response/MoimInvitationInfoResponse.java +++ b/module-domain/src/main/java/com/mile/moim/service/dto/response/MoimInvitationInfoResponse.java @@ -1,7 +1,7 @@ package com.mile.moim.service.dto.response; import com.mile.moim.domain.Moim; -import com.mile.utils.DateUtil; +import com.mile.common.utils.DateUtil; public record MoimInvitationInfoResponse( String moimTitle, diff --git a/module-domain/src/main/java/com/mile/moim/service/dto/response/MoimMostCuriousPostResponse.java b/module-domain/src/main/java/com/mile/moim/service/dto/response/MoimMostCuriousPostResponse.java index def320f7..15d9e1c8 100644 --- a/module-domain/src/main/java/com/mile/moim/service/dto/response/MoimMostCuriousPostResponse.java +++ b/module-domain/src/main/java/com/mile/moim/service/dto/response/MoimMostCuriousPostResponse.java @@ -1,6 +1,7 @@ package com.mile.moim.service.dto.response; -import com.mile.utils.JsoupUtil; +import com.mile.moim.domain.popular.MoimCuriousPost; +import com.mile.common.utils.JsoupUtil; public record MoimMostCuriousPostResponse( String postId, @@ -14,14 +15,10 @@ public record MoimMostCuriousPostResponse( private static final int SUBSTRING_END = 400; public static MoimMostCuriousPostResponse of( - String postId, - String imageUrl, - String topic, - String title, - String content, - boolean isContainPhoto - ) { - return new MoimMostCuriousPostResponse(postId, imageUrl, topic, title, getSubStringOfCleanContent(content), isContainPhoto); + final MoimCuriousPost post + ) { + return new MoimMostCuriousPostResponse(post.getIdUrl(), post.getImgUrl(), post.getTopic(), + post.getTitle(), getSubStringOfCleanContent(post.getContents()), post.isContainPhoto()); } private static String getSubStringOfCleanContent( diff --git a/module-domain/src/main/java/com/mile/moim/service/dto/response/PopularWriterListResponse.java b/module-domain/src/main/java/com/mile/moim/service/dto/response/MoimMostCuriousWriterResponse.java similarity index 56% rename from module-domain/src/main/java/com/mile/moim/service/dto/response/PopularWriterListResponse.java rename to module-domain/src/main/java/com/mile/moim/service/dto/response/MoimMostCuriousWriterResponse.java index 09ba3480..17c2ef0e 100644 --- a/module-domain/src/main/java/com/mile/moim/service/dto/response/PopularWriterListResponse.java +++ b/module-domain/src/main/java/com/mile/moim/service/dto/response/MoimMostCuriousWriterResponse.java @@ -1,14 +1,15 @@ package com.mile.moim.service.dto.response; +import com.mile.moim.domain.popular.MoimCuriousWriter; import com.mile.writername.domain.WriterName; import com.mile.writername.service.dto.response.PopularWriterResponse; import java.util.List; import java.util.stream.Collectors; -public record PopularWriterListResponse(List popularWriters) { +public record MoimMostCuriousWriterResponse(List popularWriters) { - public static PopularWriterListResponse of(final List writers) { - return new PopularWriterListResponse( + public static MoimMostCuriousWriterResponse of(final List writers) { + return new MoimMostCuriousWriterResponse( writers .stream() .map(PopularWriterResponse::of) diff --git a/module-domain/src/main/java/com/mile/moim/service/dto/response/MoimOverallInfoResponse.java b/module-domain/src/main/java/com/mile/moim/service/dto/response/MoimOverallInfoResponse.java new file mode 100644 index 00000000..2ea71076 --- /dev/null +++ b/module-domain/src/main/java/com/mile/moim/service/dto/response/MoimOverallInfoResponse.java @@ -0,0 +1,8 @@ +package com.mile.moim.service.dto.response; + +public record MoimOverallInfoResponse( + MoimInfoResponse infoResponse, + MoimCuriousPostListResponse mostCuriousPost, + MoimMostCuriousWriterResponse mostCuriousWriter +) { +} diff --git a/module-domain/src/main/java/com/mile/moim/service/dto/response/MoimTopicInfoResponse.java b/module-domain/src/main/java/com/mile/moim/service/dto/response/MoimTopicInfoResponse.java index 36ec12dd..f17d7f8a 100644 --- a/module-domain/src/main/java/com/mile/moim/service/dto/response/MoimTopicInfoResponse.java +++ b/module-domain/src/main/java/com/mile/moim/service/dto/response/MoimTopicInfoResponse.java @@ -1,7 +1,7 @@ package com.mile.moim.service.dto.response; import com.mile.topic.domain.Topic; -import com.mile.utils.DateUtil; +import com.mile.common.utils.DateUtil; public record MoimTopicInfoResponse( String topicId, diff --git a/module-domain/src/main/java/com/mile/moim/service/popular/MoimPopularInfoService.java b/module-domain/src/main/java/com/mile/moim/service/popular/MoimPopularInfoService.java new file mode 100644 index 00000000..e421deb8 --- /dev/null +++ b/module-domain/src/main/java/com/mile/moim/service/popular/MoimPopularInfoService.java @@ -0,0 +1,64 @@ +package com.mile.moim.service.popular; + +import com.mile.curious.repository.dto.PostAndCuriousCountInLastWeek; +import com.mile.curious.service.CuriousRetriever; +import com.mile.moim.domain.Moim; +import com.mile.moim.domain.popular.MoimCuriousPost; +import com.mile.moim.domain.popular.MoimCuriousWriter; +import com.mile.moim.domain.popular.MoimPopularInfo; +import com.mile.moim.repository.MoimPopularInfoRepository; +import com.mile.writername.domain.WriterName; +import lombok.AccessLevel; +import lombok.RequiredArgsConstructor; +import org.springframework.cache.annotation.CachePut; +import org.springframework.cache.annotation.Cacheable; +import org.springframework.stereotype.Service; + +import java.util.List; +import java.util.Map; +import java.util.stream.Collectors; + +@Service +@RequiredArgsConstructor(access = AccessLevel.PROTECTED) +public class MoimPopularInfoService { + private final MoimPopularInfoRepository moimPopularInfoRepository; + private final CuriousRetriever curiousRetriever; + + @CachePut(value = "moimPopularInfo", key = "#moim.id") + public MoimPopularInfo setMostPopularInfoOfMoim(final Moim moim) { + List mostCuriousPostsInLastWeek = curiousRetriever.findMostCuriousPostsInLastWeek(moim); + + List moimCuriousPosts = getMoimCuriousPost(mostCuriousPostsInLastWeek); + + List moimCuriousWriters = getMoimCuriousWriter(mostCuriousPostsInLastWeek); + + MoimPopularInfo moimPopularInfo = MoimPopularInfo.of(moim.getId(), moimCuriousPosts, moimCuriousWriters); + + return moimPopularInfoRepository.save(moimPopularInfo); + } + + private List getMoimCuriousPost(final List mostCuriousPostsInLastWeek) { + return mostCuriousPostsInLastWeek.stream().map(p -> + MoimCuriousPost.of(p.getPost())).limit(2).toList(); + } + + private List getMoimCuriousWriter(final List mostCuriousPostsInLastWeek) { + Map writerNameCount = mostCuriousPostsInLastWeek.stream() + .collect(Collectors.groupingBy(p -> p.getPost().getWriterName(), Collectors.summingLong(PostAndCuriousCountInLastWeek::getCount))); + + List topTwoWriters = writerNameCount.entrySet().stream() + .sorted(Map.Entry.comparingByValue()) + .limit(2) + .map(Map.Entry::getKey).toList(); + + return topTwoWriters.stream().map(MoimCuriousWriter::of).toList(); + } + + @Cacheable(value = "moimPopularInfo", key = "#moim.id") + public MoimPopularInfo getMoimPopularInfo(final Moim moim) { + return moimPopularInfoRepository.findByMoimId(moim.getId()).orElseGet( + () -> setMostPopularInfoOfMoim(moim) + ); + } + +} diff --git a/module-domain/src/main/java/com/mile/post/domain/Post.java b/module-domain/src/main/java/com/mile/post/domain/Post.java index ff850fe7..7283cbe6 100644 --- a/module-domain/src/main/java/com/mile/post/domain/Post.java +++ b/module-domain/src/main/java/com/mile/post/domain/Post.java @@ -1,6 +1,6 @@ package com.mile.post.domain; -import com.mile.config.BaseTimeEntity; +import com.mile.common.config.BaseTimeEntity; import com.mile.post.service.dto.request.PostPutRequest; import com.mile.topic.domain.Topic; import com.mile.writername.domain.WriterName; diff --git a/module-domain/src/main/java/com/mile/post/repository/PostRepositoryCustomImpl.java b/module-domain/src/main/java/com/mile/post/repository/PostRepositoryCustomImpl.java index 277a9a93..6f9ea3f1 100644 --- a/module-domain/src/main/java/com/mile/post/repository/PostRepositoryCustomImpl.java +++ b/module-domain/src/main/java/com/mile/post/repository/PostRepositoryCustomImpl.java @@ -24,7 +24,6 @@ public class PostRepositoryCustomImpl implements PostRepositoryCustom { private final JPAQueryFactory jpaQueryFactory; - // select p from post p join moim m on p.topic = m.topic orderby p.curiousCount limit 2 public List findTop2ByMoimOrderByCuriousCountDesc(final Moim requestMoim) { return jpaQueryFactory .selectFrom(post) @@ -36,7 +35,6 @@ public List findTop2ByMoimOrderByCuriousCountDesc(final Moim requestMoim) .fetch(); } - public List findLatest4NonTemporaryPostsByMoim(Moim moim) { List result = jpaQueryFactory diff --git a/module-domain/src/main/java/com/mile/post/service/PostCreator.java b/module-domain/src/main/java/com/mile/post/service/PostCreator.java index 0405b33d..6917e9cb 100644 --- a/module-domain/src/main/java/com/mile/post/service/PostCreator.java +++ b/module-domain/src/main/java/com/mile/post/service/PostCreator.java @@ -5,7 +5,7 @@ import com.mile.post.service.dto.request.PostCreateRequest; import com.mile.post.service.dto.request.TemporaryPostCreateRequest; import com.mile.topic.domain.Topic; -import com.mile.utils.SecureUrlUtil; +import com.mile.common.utils.SecureUrlUtil; import com.mile.writername.domain.WriterName; import lombok.RequiredArgsConstructor; import org.springframework.stereotype.Service; diff --git a/module-domain/src/main/java/com/mile/post/service/PostRetriever.java b/module-domain/src/main/java/com/mile/post/service/PostRetriever.java index 22c47e8d..41e08df0 100644 --- a/module-domain/src/main/java/com/mile/post/service/PostRetriever.java +++ b/module-domain/src/main/java/com/mile/post/service/PostRetriever.java @@ -4,12 +4,13 @@ import com.mile.exception.model.ForbiddenException; import com.mile.exception.model.NotFoundException; import com.mile.moim.domain.Moim; +import com.mile.moim.domain.popular.MoimCuriousPost; import com.mile.moim.service.dto.response.MoimCuriousPostListResponse; import com.mile.moim.service.dto.response.MoimMostCuriousPostResponse; import com.mile.post.domain.Post; import com.mile.post.repository.PostRepository; import com.mile.topic.domain.Topic; -import com.mile.utils.SecureUrlUtil; +import com.mile.common.utils.SecureUrlUtil; import com.mile.writername.domain.WriterName; import com.mile.writername.service.WriterNameRetriever; import lombok.RequiredArgsConstructor; @@ -78,31 +79,6 @@ private List getPostHaveCuriousCount( return postList; } - public void authenticateUserWithPostId( - final Long postId, - final Long userId - ) { - Post post = findById(postId); - authenticateUserWithPost(post, userId); - } - - public void authenticateUserWithPost( - final Post post, - final Long userId - ) { - Long moimId = post.getTopic().getMoim().getId(); - writerNameRetriever.findByMoimAndUserWithNotExceptionCase(moimId, userId); - } - - public void authenticateUserOfMoim( - final boolean isUserInMoim - ) { - if (!isUserInMoim) { - throw new ForbiddenException(ErrorMessage.USER_MOIM_AUTHENTICATE_ERROR); - } - } - - public boolean existsPostByWriterWithPost( final Long postId, final Long writerNameId @@ -119,27 +95,20 @@ public void authenticateWriterWithPost( } } - public void authenticateWriter( - final Long postId, - final WriterName writerName - ) { - authenticateWriterWithPost(postId, writerName.getId()); - } public boolean isWriterOfPost(final Post post, final WriterName writerName) { return post.getWriterName().equals(writerName); } - public MoimCuriousPostListResponse getMostCuriousPostByMoim(final Moim moim) { List postList = getPostHaveCuriousCount(postRepository.findTop2ByMoimOrderByCuriousCountDesc(moim)); return MoimCuriousPostListResponse.of(postList .stream() - .map(p -> - MoimMostCuriousPostResponse.of(p.getIdUrl(), p.getImageUrl(), p.getTopic().getContent(), p.getTitle(), p.getContent(), p.isContainPhoto()) - ).collect(Collectors.toList())); + .map(p->MoimMostCuriousPostResponse.of(MoimCuriousPost.of(p)) + ).toList()); } + public int findPostCountByWriterNameId( final Long writerNameId ) { @@ -153,5 +122,4 @@ public List findAllByTopics( .flatMap(topic -> postRepository.findByTopic(topic).stream()) .collect(Collectors.toList()); } - } diff --git a/module-domain/src/main/java/com/mile/post/service/PostService.java b/module-domain/src/main/java/com/mile/post/service/PostService.java index c48952fc..85a66f2c 100644 --- a/module-domain/src/main/java/com/mile/post/service/PostService.java +++ b/module-domain/src/main/java/com/mile/post/service/PostService.java @@ -26,15 +26,18 @@ import com.mile.topic.service.TopicRetriever; import com.mile.topic.service.TopicService; import com.mile.topic.service.dto.response.ContentWithIsSelectedResponse; -import com.mile.utils.SecureUrlUtil; +import com.mile.common.utils.SecureUrlUtil; +import com.mile.util.MoimWriterNameMapUtil; import com.mile.writername.domain.WriterName; import com.mile.writername.service.WriterNameRetriever; import com.mile.writername.service.dto.response.WriterNameResponse; +import com.mile.writername.service.vo.WriterNameInfo; import lombok.RequiredArgsConstructor; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; import java.util.Base64; +import java.util.HashMap; import java.util.List; @@ -67,64 +70,75 @@ public class PostService { @Transactional public void createCommentOnPost( final Long postId, - final Long userId, + final HashMap moimWriterInfoMap, final CommentCreateRequest commentCreateRequest ) { Post post = postRetriever.findById(postId); final Long moimId = post.getTopic().getMoim().getId(); - postRetriever.authenticateUserWithPost(post, userId); - commentCreator.createComment(post, writerNameRetriever.findByMoimAndUser(moimId, userId), commentCreateRequest); + final Long writerNameId = MoimWriterNameMapUtil.getWriterNameIdMoimWriterNameMap(moimId, moimWriterInfoMap); + commentCreator.createComment(post, writerNameRetriever.findByIdNonException(writerNameId), commentCreateRequest); } @Transactional public PostCuriousResponse createCuriousOnPost( final Long postId, - final Long userId + final HashMap moimWriterNameMap ) { Post post = postRetriever.findById(postId); Long moimId = post.getTopic().getMoim().getId(); - postRetriever.authenticateUserWithPost(post, userId); - curiousService.createCurious(post, writerNameRetriever.findByMoimAndUser(moimId, userId)); + final Long writerNameId = MoimWriterNameMapUtil.getWriterNameIdMoimWriterNameMap(moimId, moimWriterNameMap); + curiousService.createCurious(post, writerNameRetriever.findById(writerNameId)); return PostCuriousResponse.of(CURIOUS_TRUE); } public CommentListResponse getComments( final Long postId, - final Long userId + final HashMap moimWriterNameMap ) { Post post = postRetriever.findById(postId); - return CommentListResponse.of(commentService.getCommentResponse(post.getTopic().getMoim().getId(), post, userId)); + final Long writerNameId = MoimWriterNameMapUtil.getWriterNameIdMoimWriterNameMap( + post.getTopic().getMoim().getId(), + moimWriterNameMap + ); + return CommentListResponse.of(commentService.getCommentResponse(post, writerNameId)); } @Transactional(readOnly = true) public CuriousInfoResponse getCuriousInfoOfPost( final Long postId, - final Long userId + final HashMap moimWriterNameMap ) { Post post = postRetriever.findById(postId); - postRetriever.authenticateUserWithPost(post, userId); - return curiousService.getCuriousInfoOfPostAndWriterName(post, writerNameRetriever.findByMoimAndUser(post.getTopic().getMoim().getId(), userId)); + final Long writerNameId = MoimWriterNameMapUtil.getWriterNameIdMoimWriterNameMap( + post.getTopic().getMoim().getId(), + moimWriterNameMap + ); + return curiousService.getCuriousInfoOfPostAndWriterName(post, writerNameRetriever.findById(writerNameId)); } @Transactional public PostCuriousResponse deleteCuriousOnPost( final Long postId, - final Long userId + final HashMap moimWriterNameMap ) { Post post = postRetriever.findById(postId); - curiousService.deleteCurious(post, writerNameRetriever.findByMoimAndUserWithNotExceptionCase(post.getTopic().getMoim().getId(), userId)); + final Long writerNameId = MoimWriterNameMapUtil.getWriterNameIdMoimWriterNameMap( + post.getTopic().getMoim().getId(), + moimWriterNameMap); + curiousService.deleteCurious(post, writerNameRetriever.findByIdNonException(writerNameId)); return PostCuriousResponse.of(CURIOUS_FALSE); } public void updatePost( final Long postId, - final Long userId, + final HashMap moimWriteNameMap, final PostPutRequest putRequest ) { Post post = postRetriever.findById(postId); - postRetriever.authenticateWriter(postId, - writerNameRetriever.findWriterNameByMoimIdAndUserId(post.getTopic().getMoim().getId(), userId)); + final Long moimId = post.getTopic().getMoim().getId(); + final Long writerNameId = MoimWriterNameMapUtil.getWriterNameIdMoimWriterNameMap(moimId, moimWriteNameMap); + postRetriever.authenticateWriterWithPost(postId, writerNameId); Topic topic = topicRetriever.findById(decodeUrlToLong(putRequest.topicId())); postUpdator.update(post, topic, putRequest); } @@ -162,7 +176,7 @@ public void deletePost( Post post = postRetriever.findById(postId); Long moimId = post.getTopic().getMoim().getId(); WriterName writerName = writerNameRetriever.findByMoimAndUser(moimId, userId); - if(!postRetriever.isWriterOfPost(post, writerName) && !moimRetriever.isMoimOwnerEqualsUser(post.getTopic().getMoim(), userId)){ + if (!postRetriever.isWriterOfPost(post, writerName) && !moimRetriever.isMoimOwnerEqualsUser(post.getTopic().getMoim(), userId)) { throw new ForbiddenException(ErrorMessage.WRITER_AUTHENTICATE_ERROR); } postRemover.delete(post); @@ -171,12 +185,13 @@ public void deletePost( @Transactional(readOnly = true) public TemporaryPostGetResponse getTemporaryPost( final Long postId, - final Long userId + final HashMap moimWriterNameMap ) { Post post = postRetriever.findById(postId); Topic selectedTopic = post.getTopic(); Moim moim = selectedTopic.getMoim(); - postRetriever.authenticateWriter(postId, writerNameRetriever.findByMoimAndUser(moim.getId(), userId)); + final Long writerNameId = MoimWriterNameMapUtil.getWriterNameIdMoimWriterNameMap(moim.getId(), moimWriterNameMap); + postRetriever.authenticateWriterWithPost(postId, writerNameId); isPostTemporary(post); List contentResponse = topicService.getContentsWithIsSelectedFromMoim(moim.getId(), selectedTopic.getId()); return TemporaryPostGetResponse.of(post, contentResponse); @@ -211,9 +226,11 @@ private Long decodeUrlToLong( return Long.parseLong(new String(Base64.getUrlDecoder().decode(url))); } - public void deleteTemporaryPost(final Long userId, final Long postId) { - Long moimId = getMoimIdFromPostId(postId); - postRetriever.authenticateWriter(postId, writerNameRetriever.findByMoimAndUser(moimId, userId)); + public void deleteTemporaryPost(final Long postId, + final HashMap moimWriterNameMap) { + final Long moimId = getMoimIdFromPostId(postId); + final Long writerNameId = MoimWriterNameMapUtil.getWriterNameIdMoimWriterNameMap(moimId, moimWriterNameMap); + postRetriever.authenticateWriterWithPost(postId, writerNameId); Post post = postRetriever.findById(postId); postRemover.deleteTemporaryPost(post); } @@ -242,11 +259,14 @@ public void createTemporaryPost( postCreator.createTemporaryPost(writerName, topic, temporaryPostCreateRequest); } + /* + FIX ME 아래 메서드는 리턴 값에 writerName의 name이 포함되어야 해서 Interceptor 인가가 필요 없을 듯 함 + * */ @Transactional public WriterNameResponse putTemporaryToFixedPost(final Long userId, final PostPutRequest request, final Long postId) { Post post = postRetriever.findById(postId); WriterName writerName = writerNameRetriever.findByMoimAndUser(post.getTopic().getMoim().getId(), userId); - postRetriever.authenticateWriter(postId, writerName); + postRetriever.authenticateWriterWithPost(postId, writerName.getId()); isPostTemporary(post); postUpdator.updateTemporaryPost(post, post.getTopic(), request); return WriterNameResponse.of(post.getIdUrl(), writerName.getName()); @@ -254,10 +274,12 @@ public WriterNameResponse putTemporaryToFixedPost(final Long userId, final PostP public ModifyPostGetResponse getPostForModifying( final Long postId, - final Long userId + final HashMap moimWriterNameMap ) { Post post = postRetriever.findById(postId); - postRetriever.authenticateUserWithPost(post, userId); + final Long moimId = post.getTopic().getMoim().getId(); + final Long writerNameId = MoimWriterNameMapUtil.getWriterNameIdMoimWriterNameMap(moimId, moimWriterNameMap); + postRetriever.authenticateWriterWithPost(post.getId(), writerNameId); isPostNotTemporary(post); List contentResponse = topicService.getContentsWithIsSelectedFromMoim(post.getTopic().getMoim().getId(), post.getTopic().getId()); return ModifyPostGetResponse.of(post, contentResponse); diff --git a/module-domain/src/main/java/com/mile/post/service/dto/response/PostGetResponse.java b/module-domain/src/main/java/com/mile/post/service/dto/response/PostGetResponse.java index 676997e1..df5770a4 100644 --- a/module-domain/src/main/java/com/mile/post/service/dto/response/PostGetResponse.java +++ b/module-domain/src/main/java/com/mile/post/service/dto/response/PostGetResponse.java @@ -2,7 +2,7 @@ import com.mile.moim.domain.Moim; import com.mile.post.domain.Post; -import com.mile.utils.DateUtil; +import com.mile.common.utils.DateUtil; public record PostGetResponse( String topic, diff --git a/module-domain/src/main/java/com/mile/post/service/dto/response/PostListResponse.java b/module-domain/src/main/java/com/mile/post/service/dto/response/PostListResponse.java index c2d7f93d..9a6cf15f 100644 --- a/module-domain/src/main/java/com/mile/post/service/dto/response/PostListResponse.java +++ b/module-domain/src/main/java/com/mile/post/service/dto/response/PostListResponse.java @@ -1,9 +1,8 @@ package com.mile.post.service.dto.response; import com.mile.post.domain.Post; -import com.mile.utils.DateUtil; -import org.jsoup.Jsoup; -import org.jsoup.safety.Safelist; +import com.mile.common.utils.DateUtil; +import com.mile.common.utils.JsoupUtil; public record PostListResponse( String postId, @@ -38,7 +37,7 @@ private static String getWriterName(final Post post) { } private static String getSubString(final Post post) { - String cleanContent = Jsoup.clean(post.getContent(), Safelist.none()); + String cleanContent = JsoupUtil.toPlainText(post.getContent()); if (cleanContent.length() >= SUBSTRING_END) { return cleanContent.substring(SUBSTRING_START, SUBSTRING_END); } else { diff --git a/module-domain/src/main/java/com/mile/topic/domain/Topic.java b/module-domain/src/main/java/com/mile/topic/domain/Topic.java index 5bde4c15..f198670e 100644 --- a/module-domain/src/main/java/com/mile/topic/domain/Topic.java +++ b/module-domain/src/main/java/com/mile/topic/domain/Topic.java @@ -1,6 +1,6 @@ package com.mile.topic.domain; -import com.mile.config.BaseTimeEntity; +import com.mile.common.config.BaseTimeEntity; import com.mile.moim.domain.Moim; import com.mile.moim.service.dto.request.TopicCreateRequest; import com.mile.topic.service.dto.request.TopicPutRequest; diff --git a/module-domain/src/main/java/com/mile/topic/service/TopicCreator.java b/module-domain/src/main/java/com/mile/topic/service/TopicCreator.java index c6a19220..e6c4f89b 100644 --- a/module-domain/src/main/java/com/mile/topic/service/TopicCreator.java +++ b/module-domain/src/main/java/com/mile/topic/service/TopicCreator.java @@ -4,7 +4,7 @@ import com.mile.moim.service.dto.request.TopicCreateRequest; import com.mile.topic.domain.Topic; import com.mile.topic.repository.TopicRepository; -import com.mile.utils.SecureUrlUtil; +import com.mile.common.utils.SecureUrlUtil; import jakarta.transaction.Transactional; import lombok.RequiredArgsConstructor; import org.springframework.stereotype.Component; diff --git a/module-domain/src/main/java/com/mile/topic/service/TopicRetriever.java b/module-domain/src/main/java/com/mile/topic/service/TopicRetriever.java index c4734747..e2f01789 100644 --- a/module-domain/src/main/java/com/mile/topic/service/TopicRetriever.java +++ b/module-domain/src/main/java/com/mile/topic/service/TopicRetriever.java @@ -2,7 +2,7 @@ import com.mile.comment.service.CommentRetriever; import com.mile.commentreply.service.CommentReplyRetriever; -import com.mile.config.BaseTimeEntity; +import com.mile.common.config.BaseTimeEntity; import com.mile.exception.message.ErrorMessage; import com.mile.exception.model.BadRequestException; import com.mile.exception.model.ForbiddenException; @@ -23,7 +23,7 @@ import com.mile.topic.service.dto.response.TopicResponse; import com.mile.user.domain.User; import com.mile.user.service.UserRetriever; -import com.mile.utils.SecureUrlUtil; +import com.mile.common.utils.SecureUrlUtil; import lombok.RequiredArgsConstructor; import org.springframework.data.domain.Page; import org.springframework.data.domain.PageRequest; @@ -141,7 +141,7 @@ private void checkTopicListEmpty( final List topicList ) { if (topicList.isEmpty()) { - throw new NotFoundException(ErrorMessage.KEYWORD_NOT_FOUND); + throw new NotFoundException(ErrorMessage.TOPIC_NOT_FOUND); } } @@ -186,7 +186,7 @@ public String findLatestTopicByMoim( ) { return topicRepository.findLatestTopicByMoim(moim) .orElseThrow( - () -> new NotFoundException(ErrorMessage.MOIM_TOPIC_NOT_FOUND) + () -> new NotFoundException(ErrorMessage.TOPIC_NOT_FOUND) ); } diff --git a/module-domain/src/main/java/com/mile/topic/service/dto/response/TopicDetailResponse.java b/module-domain/src/main/java/com/mile/topic/service/dto/response/TopicDetailResponse.java index 30958ab4..ff785338 100644 --- a/module-domain/src/main/java/com/mile/topic/service/dto/response/TopicDetailResponse.java +++ b/module-domain/src/main/java/com/mile/topic/service/dto/response/TopicDetailResponse.java @@ -1,7 +1,7 @@ package com.mile.topic.service.dto.response; import com.mile.topic.domain.Topic; -import com.mile.utils.DateUtil; +import com.mile.common.utils.DateUtil; public record TopicDetailResponse( String topicName, diff --git a/module-domain/src/main/java/com/mile/user/service/UserService.java b/module-domain/src/main/java/com/mile/user/service/UserService.java index eae62fe2..64b59004 100644 --- a/module-domain/src/main/java/com/mile/user/service/UserService.java +++ b/module-domain/src/main/java/com/mile/user/service/UserService.java @@ -4,11 +4,14 @@ import com.mile.moim.service.dto.response.MoimListOfUserResponse; import com.mile.moim.service.dto.response.MoimOfUserResponse; import com.mile.user.domain.User; +import com.mile.writername.domain.MoimRole; import com.mile.writername.service.WriterNameRetriever; import com.mile.writername.service.WriterNameService; +import com.mile.writername.service.vo.WriterNameInfo; import lombok.RequiredArgsConstructor; import org.springframework.stereotype.Service; +import java.util.Map; import java.util.stream.Collectors; @Service @@ -48,4 +51,8 @@ public MoimListOfUserResponse getMoimOfUserList(final Long userId) { .map(MoimOfUserResponse::of) .collect(Collectors.toList())); } + + public Map getJoinedRoleFromUser(final Long userId) { + return writerNameRetriever.getJoinedRoleFromUserId(userId); + } } diff --git a/module-domain/src/main/java/com/mile/util/MoimWriterNameMapUtil.java b/module-domain/src/main/java/com/mile/util/MoimWriterNameMapUtil.java new file mode 100644 index 00000000..b6afdac4 --- /dev/null +++ b/module-domain/src/main/java/com/mile/util/MoimWriterNameMapUtil.java @@ -0,0 +1,29 @@ +package com.mile.util; + +import com.mile.exception.message.ErrorMessage; +import com.mile.exception.model.ForbiddenException; +import com.mile.writername.service.vo.WriterNameInfo; + +import java.util.HashMap; + +public class MoimWriterNameMapUtil { + + public static Long getWriterNameIdMoimWriterNameMap( + final Long moimId, + final HashMap moimWriterInfoMap + ) { + if(!moimWriterInfoMap.containsKey(moimId)) { + throw new ForbiddenException(ErrorMessage.WRITER_NAME_NON_AUTHENTICATE); + } + return moimWriterInfoMap.get(moimId).writerNameId(); + } + + public static void authenticateWriterName( + final Long moimId, + final HashMap moimWriterInfoMap + ) { + if(!moimWriterInfoMap.containsKey(moimId)) { + throw new ForbiddenException(ErrorMessage.WRITER_NAME_NON_AUTHENTICATE); + } + } +} diff --git a/module-domain/src/main/java/com/mile/writername/domain/MoimRole.java b/module-domain/src/main/java/com/mile/writername/domain/MoimRole.java new file mode 100644 index 00000000..fb0f3f07 --- /dev/null +++ b/module-domain/src/main/java/com/mile/writername/domain/MoimRole.java @@ -0,0 +1,14 @@ +package com.mile.writername.domain; + +import lombok.AllArgsConstructor; +import lombok.Getter; + +@AllArgsConstructor +@Getter +public enum MoimRole { + + WRITER("WRITER"), + OWNER("OWNER"); + + private final String role; +} diff --git a/module-domain/src/main/java/com/mile/writername/domain/RandomWriterNamePrefix.java b/module-domain/src/main/java/com/mile/writername/domain/RandomWriterNamePrefix.java deleted file mode 100644 index 19a8fc29..00000000 --- a/module-domain/src/main/java/com/mile/writername/domain/RandomWriterNamePrefix.java +++ /dev/null @@ -1,18 +0,0 @@ -package com.mile.writername.domain; - -import jakarta.persistence.Entity; -import jakarta.persistence.GeneratedValue; -import jakarta.persistence.GenerationType; -import jakarta.persistence.Id; -import lombok.Getter; - -@Entity -@Getter -public class RandomWriterNamePrefix { - - @Id - @GeneratedValue(strategy = GenerationType.IDENTITY) - private Long id; - - private String prefix; -} diff --git a/module-domain/src/main/java/com/mile/writername/domain/RandomWriterNameSuffix.java b/module-domain/src/main/java/com/mile/writername/domain/RandomWriterNameSuffix.java deleted file mode 100644 index 1535b1bc..00000000 --- a/module-domain/src/main/java/com/mile/writername/domain/RandomWriterNameSuffix.java +++ /dev/null @@ -1,18 +0,0 @@ -package com.mile.writername.domain; - -import jakarta.persistence.Entity; -import jakarta.persistence.GeneratedValue; -import jakarta.persistence.GenerationType; -import jakarta.persistence.Id; -import lombok.Getter; - -@Entity -@Getter -public class RandomWriterNameSuffix { - - @Id - @GeneratedValue(strategy = GenerationType.IDENTITY) - private Long id; - - private String suffix; -} diff --git a/module-domain/src/main/java/com/mile/writername/repository/RandomWriterNamePrefixRepository.java b/module-domain/src/main/java/com/mile/writername/repository/RandomWriterNamePrefixRepository.java deleted file mode 100644 index 6c329d3d..00000000 --- a/module-domain/src/main/java/com/mile/writername/repository/RandomWriterNamePrefixRepository.java +++ /dev/null @@ -1,7 +0,0 @@ -package com.mile.writername.repository; - -import com.mile.writername.domain.RandomWriterNamePrefix; -import org.springframework.data.jpa.repository.JpaRepository; - -public interface RandomWriterNamePrefixRepository extends JpaRepository { -} diff --git a/module-domain/src/main/java/com/mile/writername/repository/RandomWriterNameSuffixRepository.java b/module-domain/src/main/java/com/mile/writername/repository/RandomWriterNameSuffixRepository.java deleted file mode 100644 index 3fc2a004..00000000 --- a/module-domain/src/main/java/com/mile/writername/repository/RandomWriterNameSuffixRepository.java +++ /dev/null @@ -1,7 +0,0 @@ -package com.mile.writername.repository; - -import com.mile.writername.domain.RandomWriterNameSuffix; -import org.springframework.data.jpa.repository.JpaRepository; - -public interface RandomWriterNameSuffixRepository extends JpaRepository { -} diff --git a/module-domain/src/main/java/com/mile/writername/repository/WriterNameRepository.java b/module-domain/src/main/java/com/mile/writername/repository/WriterNameRepository.java index 9a98accc..9cd120ed 100644 --- a/module-domain/src/main/java/com/mile/writername/repository/WriterNameRepository.java +++ b/module-domain/src/main/java/com/mile/writername/repository/WriterNameRepository.java @@ -6,15 +6,14 @@ import org.springframework.data.domain.Page; import org.springframework.data.domain.Pageable; import org.springframework.data.jpa.repository.JpaRepository; - -import java.util.List; -import java.util.Optional; - import org.springframework.data.jpa.repository.Modifying; import org.springframework.data.jpa.repository.Query; import org.springframework.data.repository.query.Param; import org.springframework.transaction.annotation.Transactional; +import java.util.List; +import java.util.Optional; + public interface WriterNameRepository extends JpaRepository { Optional findByMoimIdAndWriterId(final Long moimId, final Long userId); @@ -27,7 +26,9 @@ public interface WriterNameRepository extends JpaRepository { boolean existsWriterNameByMoimAndNormalizedName(final Moim moim, final String normalizedName); - List findTop2ByMoimIdAndTotalCuriousCountGreaterThanOrderByTotalCuriousCountDesc(final Long moimId, final int totalCuriousCount); + int countByMoim(final Moim moim); + + List findTop2ByMoimAndTotalCuriousCountGreaterThanOrderByTotalCuriousCountDesc(final Moim moim, final int totalCuriousCount); @Query("SELECT w FROM WriterName w WHERE w.moim.id = :moimId ORDER BY CASE WHEN w = :owner THEN 0 ELSE 1 END, w.id ASC") Page findByMoimIdOrderByOwnerFirstAndIdAsc(@Param("moimId") Long moimId, @Param("owner") WriterName owner, Pageable pageable); @@ -36,7 +37,7 @@ public interface WriterNameRepository extends JpaRepository { Optional findById(final Long id); @Query("select w from WriterName w join fetch w.moim where w.writer.id = :writerId") - List findAllByWriterId(final Long writerId); + List findAllByWriterId(final long writerId); Integer countAllByWriter(final User user); diff --git a/module-domain/src/main/java/com/mile/writername/service/WriterNameRetriever.java b/module-domain/src/main/java/com/mile/writername/service/WriterNameRetriever.java index b28077ed..6b326c1e 100644 --- a/module-domain/src/main/java/com/mile/writername/service/WriterNameRetriever.java +++ b/module-domain/src/main/java/com/mile/writername/service/WriterNameRetriever.java @@ -5,15 +5,18 @@ import com.mile.exception.model.NotFoundException; import com.mile.moim.domain.Moim; import com.mile.user.domain.User; +import com.mile.writername.domain.MoimRole; import com.mile.writername.domain.WriterName; import com.mile.writername.repository.WriterNameRepository; -import com.mile.writername.service.dto.response.WriterNameShortResponse; +import com.mile.writername.service.dto.response.WriterNameInformationResponse; +import com.mile.writername.service.vo.WriterNameInfo; import lombok.RequiredArgsConstructor; import org.springframework.data.domain.Page; import org.springframework.data.domain.PageRequest; import org.springframework.stereotype.Component; import java.util.List; +import java.util.Map; import java.util.Optional; import java.util.stream.Collectors; @@ -37,15 +40,14 @@ public List findByWriter(final User user) { public WriterName findById(final Long id) { return writerNameRepository.findById(id).orElseThrow( - () -> new NotFoundException(ErrorMessage.WRITER_NOT_FOUND) + () -> new ForbiddenException(ErrorMessage.USER_MOIM_AUTHENTICATE_ERROR) ); } - public WriterNameShortResponse findWriterNameInfo( - final Long moimId, - final Long userId + public WriterNameInformationResponse findWriterNameInfo( + final Long writerNameId ) { - return WriterNameShortResponse.of(findByMoimAndUserWithNotExceptionCase(moimId, userId)); + return WriterNameInformationResponse.of(findByIdNonException(writerNameId)); } public boolean isUserInMoim( @@ -69,12 +71,11 @@ public WriterName findByMoimAndUser( ); } - public WriterName findByMoimAndUserWithNotExceptionCase( - final Long moimId, - final Long writerId + public WriterName findByIdNonException( + final Long writerNameId ) { - return writerNameRepository.findByMoimIdAndWriterId(moimId, writerId) - .orElseThrow( () -> new ForbiddenException(ErrorMessage.WRITER_NAME_NON_AUTHENTICATE) + return writerNameRepository.findById(writerNameId) + .orElseThrow(() -> new ForbiddenException(ErrorMessage.WRITER_NAME_NON_AUTHENTICATE) ); } @@ -114,10 +115,25 @@ public int findNumbersOfWritersByMoimId( return writerNameRepository.findByMoimId(moimId).size(); } - public List findTop2ByCuriousCount(final Long moimid) { - return writerNameRepository.findTop2ByMoimIdAndTotalCuriousCountGreaterThanOrderByTotalCuriousCountDesc(moimid, MIN_TOTAL_CURIOUS_COUNT); + public int findNumbersOfWritersByMoim( + final Moim moim + ) { + return writerNameRepository.countByMoim(moim); + } + + public Map getJoinedRoleFromUserId(final Long userId) { + return writerNameRepository.findAllByWriterId(userId).stream().collect( + Collectors.toMap(writerName -> writerName.getMoim().getId(), this::getWriterNameMoimRole) + ); + } + + private WriterNameInfo getWriterNameMoimRole(final WriterName writerName) { + return WriterNameInfo.of(writerName.getId(), writerName.getMoim().getOwner().equals(writerName) ? MoimRole.OWNER : MoimRole.WRITER); } + public List findTop2ByCuriousCount(final Moim moim) { + return writerNameRepository.findTop2ByMoimAndTotalCuriousCountGreaterThanOrderByTotalCuriousCountDesc(moim, MIN_TOTAL_CURIOUS_COUNT); + } public Page findWriterNameByMoimIdOrderByOwnerFirstAndIdAsc(final Long moimId, final WriterName owner, final PageRequest pageRequest) { return writerNameRepository.findByMoimIdOrderByOwnerFirstAndIdAsc(moimId, owner, pageRequest); diff --git a/module-domain/src/main/java/com/mile/writername/service/dto/response/PopularWriterResponse.java b/module-domain/src/main/java/com/mile/writername/service/dto/response/PopularWriterResponse.java index efdf8aec..ea959931 100644 --- a/module-domain/src/main/java/com/mile/writername/service/dto/response/PopularWriterResponse.java +++ b/module-domain/src/main/java/com/mile/writername/service/dto/response/PopularWriterResponse.java @@ -1,9 +1,9 @@ package com.mile.writername.service.dto.response; -import com.mile.writername.domain.WriterName; +import com.mile.moim.domain.popular.MoimCuriousWriter; -public record PopularWriterResponse(String writerName, String information) { - public static PopularWriterResponse of(WriterName writer) { - return new PopularWriterResponse(writer.getName(), writer.getInformation()); +public record PopularWriterResponse(String writerName) { + public static PopularWriterResponse of(MoimCuriousWriter writer) { + return new PopularWriterResponse(writer.getName()); } } diff --git a/module-domain/src/main/java/com/mile/writername/service/dto/response/WriterNameInformationResponse.java b/module-domain/src/main/java/com/mile/writername/service/dto/response/WriterNameInformationResponse.java new file mode 100644 index 00000000..11f9dac8 --- /dev/null +++ b/module-domain/src/main/java/com/mile/writername/service/dto/response/WriterNameInformationResponse.java @@ -0,0 +1,13 @@ +package com.mile.writername.service.dto.response; + +import com.mile.writername.domain.WriterName; + +public record WriterNameInformationResponse( + String writerName, + Long writerNameId, + String description +) { + public static WriterNameInformationResponse of(final WriterName writerName) { + return new WriterNameInformationResponse(writerName.getName(), writerName.getId(), writerName.getInformation()); + } +} diff --git a/module-domain/src/main/java/com/mile/writername/service/dto/response/WriterNameShortResponse.java b/module-domain/src/main/java/com/mile/writername/service/dto/response/WriterNameShortResponse.java deleted file mode 100644 index f79cad12..00000000 --- a/module-domain/src/main/java/com/mile/writername/service/dto/response/WriterNameShortResponse.java +++ /dev/null @@ -1,12 +0,0 @@ -package com.mile.writername.service.dto.response; - -import com.mile.writername.domain.WriterName; - -public record WriterNameShortResponse( - String writerName, - Long writerNameId -) { - public static WriterNameShortResponse of(final WriterName writerName) { - return new WriterNameShortResponse(writerName.getName(), writerName.getId()); - } -} diff --git a/module-domain/src/main/java/com/mile/writername/service/vo/WriterNameInfo.java b/module-domain/src/main/java/com/mile/writername/service/vo/WriterNameInfo.java new file mode 100644 index 00000000..8e455f58 --- /dev/null +++ b/module-domain/src/main/java/com/mile/writername/service/vo/WriterNameInfo.java @@ -0,0 +1,12 @@ +package com.mile.writername.service.vo; + +import com.mile.writername.domain.MoimRole; + +public record WriterNameInfo( + Long writerNameId, + MoimRole moimRole +) { + public static WriterNameInfo of(final Long writerNameId, final MoimRole moimRole) { + return new WriterNameInfo(writerNameId, moimRole); + } +} \ No newline at end of file diff --git a/module-domain/src/test/java/util/JsoupUtilTest.java b/module-domain/src/test/java/util/JsoupUtilTest.java index beebe58f..eeaf4edf 100644 --- a/module-domain/src/test/java/util/JsoupUtilTest.java +++ b/module-domain/src/test/java/util/JsoupUtilTest.java @@ -1,6 +1,6 @@ package util; -import com.mile.utils.JsoupUtil; +import com.mile.common.utils.JsoupUtil; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test;