diff --git a/.github/workflows/backend-dev.yml b/.github/workflows/backend-dev.yml index bec561e00..3dbfb05d7 100644 --- a/.github/workflows/backend-dev.yml +++ b/.github/workflows/backend-dev.yml @@ -49,7 +49,7 @@ jobs: - name: Build and push run: | - docker buildx build --platform linux/arm64 -t \ + docker buildx build --platform linux/amd64 -t \ ${{ secrets.DOCKER_USERNAME }}/${{ secrets.DOCKER_IMAGE_BE_DEV }} --push . deploy: diff --git a/.github/workflows/backend-prod.yml b/.github/workflows/backend-prod.yml index 2ee300f18..719d3bf41 100644 --- a/.github/workflows/backend-prod.yml +++ b/.github/workflows/backend-prod.yml @@ -2,7 +2,7 @@ name: backend-push on: push: - branches: [ "main" ] + branches: [ "release" ] paths: - 'server/**' - '.github/workflows/**' @@ -112,10 +112,10 @@ jobs: MAX_ATTEMPTS=30 SLEEP_INTERVAL=2 ATTEMPT=1 - + while [ $ATTEMPT -le $MAX_ATTEMPTS ]; do HEALTH_STATUS=$(curl -s http://localhost:$NEXT_PORT/actuator/health | sed -n 's/.*"status":"\([^"]*\)".*/\1/p') - + if [ "$HEALTH_STATUS" = "UP" ]; then echo "Health check passed on attempt $ATTEMPT." break @@ -124,7 +124,7 @@ jobs: ATTEMPT=$((ATTEMPT+1)) sleep $SLEEP_INTERVAL fi - + if [ $ATTEMPT -gt $MAX_ATTEMPTS ]; then echo "Health check failed after $MAX_ATTEMPTS attempts. Rolling back..." sudo docker rm -f haengdong-backend-$NEXT_PORT @@ -172,7 +172,7 @@ jobs: } server { listen 9100; - + location /actuator { proxy_pass http://haengdong-backend-$NEXT_PORT:8080; proxy_set_header Host \$host; @@ -211,7 +211,7 @@ jobs: } server { listen 9100; - + location /actuator { proxy_pass http://haengdong-backend-$NEXT_PORT:8080; proxy_set_header Host \$host; diff --git a/server/build.gradle b/server/build.gradle index e101f2eaf..a12f54b6e 100644 --- a/server/build.gradle +++ b/server/build.gradle @@ -35,6 +35,7 @@ dependencies { implementation 'io.jsonwebtoken:jjwt:0.9.1' implementation 'javax.xml.bind:jaxb-api:2.3.1' + implementation 'com.auth0:java-jwt:4.4.0' compileOnly 'org.projectlombok:lombok' annotationProcessor 'org.projectlombok:lombok' diff --git a/server/src/main/java/server/haengdong/HaengdongApplication.java b/server/src/main/java/haengdong/HaengdongApplication.java similarity index 95% rename from server/src/main/java/server/haengdong/HaengdongApplication.java rename to server/src/main/java/haengdong/HaengdongApplication.java index 3e4f9fcfe..466297436 100644 --- a/server/src/main/java/server/haengdong/HaengdongApplication.java +++ b/server/src/main/java/haengdong/HaengdongApplication.java @@ -1,4 +1,4 @@ -package server.haengdong; +package haengdong; import lombok.extern.slf4j.Slf4j; import org.springframework.boot.SpringApplication; diff --git a/server/src/main/java/haengdong/common/auth/Login.java b/server/src/main/java/haengdong/common/auth/Login.java new file mode 100644 index 000000000..a9ab5bad0 --- /dev/null +++ b/server/src/main/java/haengdong/common/auth/Login.java @@ -0,0 +1,12 @@ +package haengdong.common.auth; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +@Target(ElementType.PARAMETER) +@Retention(RetentionPolicy.RUNTIME) +public @interface Login { + boolean required() default true; +} diff --git a/server/src/main/java/server/haengdong/domain/TokenProvider.java b/server/src/main/java/haengdong/common/auth/TokenProvider.java similarity index 86% rename from server/src/main/java/server/haengdong/domain/TokenProvider.java rename to server/src/main/java/haengdong/common/auth/TokenProvider.java index 28e7956c3..c514b222f 100644 --- a/server/src/main/java/server/haengdong/domain/TokenProvider.java +++ b/server/src/main/java/haengdong/common/auth/TokenProvider.java @@ -1,4 +1,4 @@ -package server.haengdong.domain; +package haengdong.common.auth; import java.util.Map; diff --git a/server/src/main/java/haengdong/common/auth/application/AuthService.java b/server/src/main/java/haengdong/common/auth/application/AuthService.java new file mode 100644 index 000000000..afe45d110 --- /dev/null +++ b/server/src/main/java/haengdong/common/auth/application/AuthService.java @@ -0,0 +1,63 @@ +package haengdong.common.auth.application; + + +import haengdong.common.auth.TokenProvider; +import haengdong.common.exception.AuthenticationException; +import haengdong.common.exception.HaengdongErrorCode; +import haengdong.event.application.EventService; +import haengdong.user.domain.Role; +import java.util.Map; +import lombok.extern.slf4j.Slf4j; + +@Slf4j +public class AuthService { + + private static final String TOKEN_NAME = "accessToken"; + private static final String CLAIM_SUB = "sub"; + private static final String ROLE = "role"; + + private final TokenProvider tokenProvider; + private final EventService eventService; + + public AuthService(TokenProvider tokenProvider, EventService eventService) { + this.tokenProvider = tokenProvider; + this.eventService = eventService; + } + + public String createGuestToken(Long userId) { + Map payload = Map.of(CLAIM_SUB, userId, ROLE, Role.GUEST); + + return tokenProvider.createToken(payload); + } + + public String createMemberToken(Long userId) { + Map payload = Map.of(CLAIM_SUB, userId, ROLE, Role.MEMBER); + + return tokenProvider.createToken(payload); + } + + public Long findUserIdByJWT(String token) { + validateToken(token); + Map payload = tokenProvider.getPayload(token); + return ((Integer) payload.get(CLAIM_SUB)).longValue(); + } + + private void validateToken(String token) { + if (!tokenProvider.validateToken(token)) { + throw new AuthenticationException(HaengdongErrorCode.TOKEN_INVALID); + } + } + + public String getTokenName() { + return TOKEN_NAME; + } + + public void checkAuth(String eventToken, Long userId) { + boolean hasEvent = eventService.existsByTokenAndUserId(eventToken, userId); + + if (!hasEvent) { + log.warn("[행사 접근 불가] Cookie EventId = {}, UserId = {}", eventToken, userId); + throw new AuthenticationException(HaengdongErrorCode.FORBIDDEN); + } + } +} diff --git a/server/src/main/java/haengdong/common/auth/config/AuthConfig.java b/server/src/main/java/haengdong/common/auth/config/AuthConfig.java new file mode 100644 index 000000000..797ca19a2 --- /dev/null +++ b/server/src/main/java/haengdong/common/auth/config/AuthConfig.java @@ -0,0 +1,36 @@ +package haengdong.common.auth.config; + +import haengdong.common.auth.TokenProvider; +import haengdong.common.auth.application.AuthService; +import haengdong.common.auth.infrastructure.AuthenticationExtractor; +import haengdong.common.auth.infrastructure.JwtTokenProvider; +import haengdong.common.properties.JwtProperties; +import haengdong.event.application.EventService; +import lombok.RequiredArgsConstructor; +import org.springframework.boot.context.properties.EnableConfigurationProperties; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; + +@RequiredArgsConstructor +@EnableConfigurationProperties({JwtProperties.class}) +@Configuration +public class AuthConfig { + + private final JwtProperties jwtProperties; + private final EventService eventService; + + @Bean + public AuthService authService() { + return new AuthService(tokenProvider(), eventService); + } + + @Bean + public TokenProvider tokenProvider() { + return new JwtTokenProvider(jwtProperties); + } + + @Bean + public AuthenticationExtractor authenticationExtractor() { + return new AuthenticationExtractor(); + } +} diff --git a/server/src/main/java/server/haengdong/config/AdminInterceptor.java b/server/src/main/java/haengdong/common/auth/infrastructure/AdminInterceptor.java similarity index 61% rename from server/src/main/java/server/haengdong/config/AdminInterceptor.java rename to server/src/main/java/haengdong/common/auth/infrastructure/AdminInterceptor.java index acfe99789..6fa34848a 100644 --- a/server/src/main/java/server/haengdong/config/AdminInterceptor.java +++ b/server/src/main/java/haengdong/common/auth/infrastructure/AdminInterceptor.java @@ -1,20 +1,23 @@ -package server.haengdong.config; +package haengdong.common.auth.infrastructure; +import haengdong.common.auth.application.AuthService; +import haengdong.common.exception.AuthenticationException; +import haengdong.common.exception.HaengdongErrorCode; import jakarta.servlet.http.HttpServletRequest; import jakarta.servlet.http.HttpServletResponse; import java.util.regex.Matcher; import java.util.regex.Pattern; +import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; import org.springframework.http.HttpMethod; import org.springframework.web.servlet.HandlerInterceptor; -import server.haengdong.application.AuthService; -import server.haengdong.exception.AuthenticationException; -import server.haengdong.exception.HaengdongErrorCode; -import server.haengdong.infrastructure.auth.AuthenticationExtractor; @Slf4j +@RequiredArgsConstructor public class AdminInterceptor implements HandlerInterceptor { + public static final String LOGIN_MEMBER_REQUEST = "loginUserId"; + private static final String ADMIN_URI_REGEX = "/api/admin/events/([^/]+)"; private static final Pattern ADMIN_URI_PATTERN = Pattern.compile(ADMIN_URI_REGEX); private static final int EVENT_TOKEN_MATCHER_INDEX = 1; @@ -22,11 +25,6 @@ public class AdminInterceptor implements HandlerInterceptor { private final AuthService authService; private final AuthenticationExtractor authenticationExtractor; - public AdminInterceptor(AuthService authService, AuthenticationExtractor authenticationExtractor) { - this.authService = authService; - this.authenticationExtractor = authenticationExtractor; - } - @Override public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) { HttpMethod method = HttpMethod.valueOf(request.getMethod()); @@ -38,19 +36,16 @@ public boolean preHandle(HttpServletRequest request, HttpServletResponse respons } private void validateToken(HttpServletRequest request) { - String token = authenticationExtractor.extract(request, authService.getTokenName()); - String tokenEventId = authService.findEventIdByToken(token); + String jwt = authenticationExtractor.extract(request, authService.getTokenName()); + Long userId = authService.findUserIdByJWT(jwt); String uri = request.getRequestURI(); - Matcher matcher = ADMIN_URI_PATTERN.matcher(uri); if (!matcher.find()) { throw new AuthenticationException(HaengdongErrorCode.FORBIDDEN); } - String eventToken = matcher.group(EVENT_TOKEN_MATCHER_INDEX); - if (!tokenEventId.equals(eventToken)) { - log.warn("[행사 접근 불가] Cookie EventId = {}, URL EventId = {}", tokenEventId, eventToken); - throw new AuthenticationException(HaengdongErrorCode.FORBIDDEN); - } + + authService.checkAuth(eventToken, userId); + request.setAttribute(LOGIN_MEMBER_REQUEST, userId); } } diff --git a/server/src/main/java/server/haengdong/infrastructure/auth/AuthenticationExtractor.java b/server/src/main/java/haengdong/common/auth/infrastructure/AuthenticationExtractor.java similarity index 80% rename from server/src/main/java/server/haengdong/infrastructure/auth/AuthenticationExtractor.java rename to server/src/main/java/haengdong/common/auth/infrastructure/AuthenticationExtractor.java index 4972de48a..d7159a9ad 100644 --- a/server/src/main/java/server/haengdong/infrastructure/auth/AuthenticationExtractor.java +++ b/server/src/main/java/haengdong/common/auth/infrastructure/AuthenticationExtractor.java @@ -1,10 +1,10 @@ -package server.haengdong.infrastructure.auth; +package haengdong.common.auth.infrastructure; import jakarta.servlet.http.Cookie; import jakarta.servlet.http.HttpServletRequest; import java.util.Arrays; -import server.haengdong.exception.AuthenticationException; -import server.haengdong.exception.HaengdongErrorCode; +import haengdong.common.exception.AuthenticationException; +import haengdong.common.exception.HaengdongErrorCode; public class AuthenticationExtractor { diff --git a/server/src/main/java/haengdong/common/auth/infrastructure/AuthenticationPrincipalArgumentResolver.java b/server/src/main/java/haengdong/common/auth/infrastructure/AuthenticationPrincipalArgumentResolver.java new file mode 100644 index 000000000..45b246d34 --- /dev/null +++ b/server/src/main/java/haengdong/common/auth/infrastructure/AuthenticationPrincipalArgumentResolver.java @@ -0,0 +1,31 @@ +package haengdong.common.auth.infrastructure; + +import haengdong.common.auth.Login; +import haengdong.common.auth.application.AuthService; +import jakarta.servlet.http.HttpServletRequest; +import lombok.RequiredArgsConstructor; +import org.springframework.core.MethodParameter; +import org.springframework.web.bind.support.WebDataBinderFactory; +import org.springframework.web.context.request.NativeWebRequest; +import org.springframework.web.method.support.HandlerMethodArgumentResolver; +import org.springframework.web.method.support.ModelAndViewContainer; + +@RequiredArgsConstructor +public class AuthenticationPrincipalArgumentResolver implements HandlerMethodArgumentResolver { + + private final AuthService authService; + private final AuthenticationExtractor authenticationExtractor; + + @Override + public boolean supportsParameter(MethodParameter parameter) { + return parameter.hasParameterAnnotation(Login.class) && parameter.getParameterType().equals(Long.class); + } + + @Override + public Long resolveArgument(MethodParameter parameter, ModelAndViewContainer mavContainer, NativeWebRequest webRequest, WebDataBinderFactory binderFactory) { + HttpServletRequest request = webRequest.getNativeRequest(HttpServletRequest.class); + String jwt = authenticationExtractor.extract(request, authService.getTokenName()); + + return authService.findUserIdByJWT(jwt); + } +} diff --git a/server/src/main/java/server/haengdong/infrastructure/auth/JwtTokenProvider.java b/server/src/main/java/haengdong/common/auth/infrastructure/JwtTokenProvider.java similarity index 63% rename from server/src/main/java/server/haengdong/infrastructure/auth/JwtTokenProvider.java rename to server/src/main/java/haengdong/common/auth/infrastructure/JwtTokenProvider.java index df9ec6a81..f8e276397 100644 --- a/server/src/main/java/server/haengdong/infrastructure/auth/JwtTokenProvider.java +++ b/server/src/main/java/haengdong/common/auth/infrastructure/JwtTokenProvider.java @@ -1,5 +1,6 @@ -package server.haengdong.infrastructure.auth; +package haengdong.common.auth.infrastructure; +import haengdong.common.properties.JwtProperties; import io.jsonwebtoken.Claims; import io.jsonwebtoken.Jws; import io.jsonwebtoken.JwtException; @@ -8,34 +9,34 @@ import java.util.Date; import java.util.HashMap; import java.util.Map; -import server.haengdong.domain.TokenProvider; +import haengdong.common.auth.TokenProvider; public class JwtTokenProvider implements TokenProvider { - private final TokenProperties tokenProperties; + private final JwtProperties jwtProperties; - public JwtTokenProvider(TokenProperties tokenProperties) { - this.tokenProperties = tokenProperties; + public JwtTokenProvider(JwtProperties jwtProperties) { + this.jwtProperties = jwtProperties; } @Override public String createToken(Map payload) { Claims claims = Jwts.claims(new HashMap<>(payload)); Date now = new Date(); - Date validity = new Date(now.getTime() + tokenProperties.expireLength()); + Date validity = new Date(now.getTime() + jwtProperties.expireLength()); return Jwts.builder() .setClaims(claims) .setIssuedAt(now) .setExpiration(validity) - .signWith(SignatureAlgorithm.HS256, tokenProperties.secretKey()) + .signWith(SignatureAlgorithm.HS256, jwtProperties.secretKey()) .compact(); } @Override public Map getPayload(String token) { return Jwts.parser() - .setSigningKey(tokenProperties.secretKey()) + .setSigningKey(jwtProperties.secretKey()) .parseClaimsJws(token) .getBody(); } @@ -43,7 +44,7 @@ public Map getPayload(String token) { @Override public boolean validateToken(String token) { try { - Jws claims = Jwts.parser().setSigningKey(tokenProperties.secretKey()).parseClaimsJws(token); + Jws claims = Jwts.parser().setSigningKey(jwtProperties.secretKey()).parseClaimsJws(token); return !claims.getBody().getExpiration().before(new Date()); } catch (JwtException | IllegalArgumentException e) { diff --git a/server/src/main/java/server/haengdong/infrastructure/DataSourceConfig.java b/server/src/main/java/haengdong/common/config/DataSourceConfig.java similarity index 96% rename from server/src/main/java/server/haengdong/infrastructure/DataSourceConfig.java rename to server/src/main/java/haengdong/common/config/DataSourceConfig.java index c859217b4..9f5877e8d 100644 --- a/server/src/main/java/server/haengdong/infrastructure/DataSourceConfig.java +++ b/server/src/main/java/haengdong/common/config/DataSourceConfig.java @@ -1,4 +1,4 @@ -package server.haengdong.infrastructure; +package haengdong.common.config; import com.zaxxer.hikari.HikariDataSource; import jakarta.persistence.EntityManagerFactory; @@ -16,6 +16,7 @@ import org.springframework.jdbc.datasource.LazyConnectionDataSourceProxy; import org.springframework.orm.jpa.JpaTransactionManager; import org.springframework.transaction.PlatformTransactionManager; +import haengdong.common.infrastructure.DynamicRoutingDataSource; @Profile("prod") @Configuration diff --git a/server/src/main/java/server/haengdong/config/JpaConfig.java b/server/src/main/java/haengdong/common/config/JpaConfig.java similarity index 85% rename from server/src/main/java/server/haengdong/config/JpaConfig.java rename to server/src/main/java/haengdong/common/config/JpaConfig.java index f0210e4b0..a895d4ffa 100644 --- a/server/src/main/java/server/haengdong/config/JpaConfig.java +++ b/server/src/main/java/haengdong/common/config/JpaConfig.java @@ -1,4 +1,4 @@ -package server.haengdong.config; +package haengdong.common.config; import org.springframework.context.annotation.Configuration; import org.springframework.data.jpa.repository.config.EnableJpaAuditing; diff --git a/server/src/main/java/haengdong/common/config/WebMvcConfig.java b/server/src/main/java/haengdong/common/config/WebMvcConfig.java new file mode 100644 index 000000000..ddd308b09 --- /dev/null +++ b/server/src/main/java/haengdong/common/config/WebMvcConfig.java @@ -0,0 +1,57 @@ +package haengdong.common.config; + +import haengdong.common.auth.application.AuthService; +import haengdong.common.auth.infrastructure.AdminInterceptor; +import haengdong.common.auth.infrastructure.AuthenticationExtractor; +import haengdong.common.auth.infrastructure.AuthenticationPrincipalArgumentResolver; +import haengdong.common.properties.CorsProperties; +import java.util.List; +import lombok.RequiredArgsConstructor; +import org.springframework.boot.context.properties.EnableConfigurationProperties; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.web.method.support.HandlerMethodArgumentResolver; +import org.springframework.web.servlet.config.annotation.CorsRegistry; +import org.springframework.web.servlet.config.annotation.InterceptorRegistry; +import org.springframework.web.servlet.config.annotation.WebMvcConfigurer; + +@RequiredArgsConstructor +@EnableConfigurationProperties({CorsProperties.class}) +@Configuration +public class WebMvcConfig implements WebMvcConfigurer { + + private final AuthService authService; + private final AuthenticationExtractor authenticationExtractor; + private final CorsProperties corsProperties; + + @Override + public void addCorsMappings(CorsRegistry registry) { + registry.addMapping("/**") + .allowedOrigins(corsProperties.allowedOrigins()) + .allowedMethods("GET", "POST", "PUT", "PATCH", "DELETE", "OPTIONS") + .allowedHeaders("*") + .allowCredentials(true) + .maxAge(corsProperties.maxAge()); + } + + @Override + public void addInterceptors(InterceptorRegistry registry) { + registry.addInterceptor(adminInterceptor()) + .addPathPatterns("/api/admin/**"); + } + + @Override + public void addArgumentResolvers(List resolvers) { + resolvers.add(authenticationPrincipalArgumentResolver()); + } + + @Bean + public AdminInterceptor adminInterceptor() { + return new AdminInterceptor(authService, authenticationExtractor); + } + + @Bean + public AuthenticationPrincipalArgumentResolver authenticationPrincipalArgumentResolver() { + return new AuthenticationPrincipalArgumentResolver(authService, authenticationExtractor); + } +} diff --git a/server/src/main/java/server/haengdong/domain/BaseEntity.java b/server/src/main/java/haengdong/common/domain/BaseEntity.java similarity index 94% rename from server/src/main/java/server/haengdong/domain/BaseEntity.java rename to server/src/main/java/haengdong/common/domain/BaseEntity.java index 2eb4aa01c..399f70a11 100644 --- a/server/src/main/java/server/haengdong/domain/BaseEntity.java +++ b/server/src/main/java/haengdong/common/domain/BaseEntity.java @@ -1,4 +1,4 @@ -package server.haengdong.domain; +package haengdong.common.domain; import jakarta.persistence.Column; import jakarta.persistence.EntityListeners; diff --git a/server/src/main/java/server/haengdong/exception/AuthenticationException.java b/server/src/main/java/haengdong/common/exception/AuthenticationException.java similarity index 92% rename from server/src/main/java/server/haengdong/exception/AuthenticationException.java rename to server/src/main/java/haengdong/common/exception/AuthenticationException.java index 2efcb16e7..f86b2dca0 100644 --- a/server/src/main/java/server/haengdong/exception/AuthenticationException.java +++ b/server/src/main/java/haengdong/common/exception/AuthenticationException.java @@ -1,4 +1,4 @@ -package server.haengdong.exception; +package haengdong.common.exception; import lombok.Getter; diff --git a/server/src/main/java/server/haengdong/exception/ErrorResponse.java b/server/src/main/java/haengdong/common/exception/ErrorResponse.java similarity index 91% rename from server/src/main/java/server/haengdong/exception/ErrorResponse.java rename to server/src/main/java/haengdong/common/exception/ErrorResponse.java index 3937f4322..981101722 100644 --- a/server/src/main/java/server/haengdong/exception/ErrorResponse.java +++ b/server/src/main/java/haengdong/common/exception/ErrorResponse.java @@ -1,4 +1,4 @@ -package server.haengdong.exception; +package haengdong.common.exception; public record ErrorResponse( String errorCode, diff --git a/server/src/main/java/server/haengdong/exception/GlobalExceptionHandler.java b/server/src/main/java/haengdong/common/exception/GlobalExceptionHandler.java similarity index 99% rename from server/src/main/java/server/haengdong/exception/GlobalExceptionHandler.java rename to server/src/main/java/haengdong/common/exception/GlobalExceptionHandler.java index 4d2c96c73..61f71d184 100644 --- a/server/src/main/java/server/haengdong/exception/GlobalExceptionHandler.java +++ b/server/src/main/java/haengdong/common/exception/GlobalExceptionHandler.java @@ -1,4 +1,4 @@ -package server.haengdong.exception; +package haengdong.common.exception; import jakarta.servlet.http.HttpServletRequest; import java.io.BufferedReader; diff --git a/server/src/main/java/server/haengdong/exception/HaengdongErrorCode.java b/server/src/main/java/haengdong/common/exception/HaengdongErrorCode.java similarity index 92% rename from server/src/main/java/server/haengdong/exception/HaengdongErrorCode.java rename to server/src/main/java/haengdong/common/exception/HaengdongErrorCode.java index 39b1014b0..751a86166 100644 --- a/server/src/main/java/server/haengdong/exception/HaengdongErrorCode.java +++ b/server/src/main/java/haengdong/common/exception/HaengdongErrorCode.java @@ -1,4 +1,4 @@ -package server.haengdong.exception; +package haengdong.common.exception; import lombok.Getter; @@ -32,6 +32,7 @@ public enum HaengdongErrorCode { IMAGE_NOT_FOUND("존재하지 않는 이미지 입니다."), IMAGE_COUNT_INVALID("이미지 수량은 %d개 까지 업로드할 수 있습니다."), + USER_NICK_NAME_LENGTH_INVALID("유저의 닉네임은 %d자 이상 %d자 이하만 입력 가능합니다."), /* Authentication */ @@ -42,6 +43,8 @@ public enum HaengdongErrorCode { FORBIDDEN("접근할 수 없는 행사입니다."), + KAKAO_LOGIN_FAIL("카카오 인증에 실패했습니다."), + /* Request Validation */ REQUEST_EMPTY("입력 값은 공백일 수 없습니다.") diff --git a/server/src/main/java/server/haengdong/exception/HaengdongException.java b/server/src/main/java/haengdong/common/exception/HaengdongException.java similarity index 94% rename from server/src/main/java/server/haengdong/exception/HaengdongException.java rename to server/src/main/java/haengdong/common/exception/HaengdongException.java index 212b5bed5..9bfed423e 100644 --- a/server/src/main/java/server/haengdong/exception/HaengdongException.java +++ b/server/src/main/java/haengdong/common/exception/HaengdongException.java @@ -1,4 +1,4 @@ -package server.haengdong.exception; +package haengdong.common.exception; import lombok.Getter; diff --git a/server/src/main/java/server/haengdong/infrastructure/DynamicRoutingDataSource.java b/server/src/main/java/haengdong/common/infrastructure/DynamicRoutingDataSource.java similarity index 93% rename from server/src/main/java/server/haengdong/infrastructure/DynamicRoutingDataSource.java rename to server/src/main/java/haengdong/common/infrastructure/DynamicRoutingDataSource.java index 5f84010a1..dbea8036a 100644 --- a/server/src/main/java/server/haengdong/infrastructure/DynamicRoutingDataSource.java +++ b/server/src/main/java/haengdong/common/infrastructure/DynamicRoutingDataSource.java @@ -1,4 +1,4 @@ -package server.haengdong.infrastructure; +package haengdong.common.infrastructure; import static org.springframework.transaction.support.TransactionSynchronizationManager.isCurrentTransactionReadOnly; diff --git a/server/src/main/java/server/haengdong/config/RequestServletFilter.java b/server/src/main/java/haengdong/common/infrastructure/RequestServletFilter.java similarity index 95% rename from server/src/main/java/server/haengdong/config/RequestServletFilter.java rename to server/src/main/java/haengdong/common/infrastructure/RequestServletFilter.java index b1afdb6f8..0819dff64 100644 --- a/server/src/main/java/server/haengdong/config/RequestServletFilter.java +++ b/server/src/main/java/haengdong/common/infrastructure/RequestServletFilter.java @@ -1,4 +1,4 @@ -package server.haengdong.config; +package haengdong.common.infrastructure; import jakarta.servlet.Filter; import jakarta.servlet.FilterChain; diff --git a/server/src/main/java/server/haengdong/infrastructure/auth/CookieProperties.java b/server/src/main/java/haengdong/common/properties/CookieProperties.java similarity index 87% rename from server/src/main/java/server/haengdong/infrastructure/auth/CookieProperties.java rename to server/src/main/java/haengdong/common/properties/CookieProperties.java index 18f867601..1020c370d 100644 --- a/server/src/main/java/server/haengdong/infrastructure/auth/CookieProperties.java +++ b/server/src/main/java/haengdong/common/properties/CookieProperties.java @@ -1,4 +1,4 @@ -package server.haengdong.infrastructure.auth; +package haengdong.common.properties; import java.time.Duration; import org.springframework.boot.context.properties.ConfigurationProperties; diff --git a/server/src/main/java/haengdong/common/properties/CorsProperties.java b/server/src/main/java/haengdong/common/properties/CorsProperties.java new file mode 100644 index 000000000..a07ad8de4 --- /dev/null +++ b/server/src/main/java/haengdong/common/properties/CorsProperties.java @@ -0,0 +1,10 @@ +package haengdong.common.properties; + +import org.springframework.boot.context.properties.ConfigurationProperties; + +@ConfigurationProperties("cors") +public record CorsProperties( + Long maxAge, + String[] allowedOrigins +) { +} diff --git a/server/src/main/java/server/haengdong/infrastructure/auth/TokenProperties.java b/server/src/main/java/haengdong/common/properties/JwtProperties.java similarity index 52% rename from server/src/main/java/server/haengdong/infrastructure/auth/TokenProperties.java rename to server/src/main/java/haengdong/common/properties/JwtProperties.java index 11dedcdbf..4502f8f86 100644 --- a/server/src/main/java/server/haengdong/infrastructure/auth/TokenProperties.java +++ b/server/src/main/java/haengdong/common/properties/JwtProperties.java @@ -1,7 +1,7 @@ -package server.haengdong.infrastructure.auth; +package haengdong.common.properties; import org.springframework.boot.context.properties.ConfigurationProperties; @ConfigurationProperties("security.jwt.token") -public record TokenProperties(String secretKey, Long expireLength) { +public record JwtProperties(String secretKey, Long expireLength) { } diff --git a/server/src/main/java/haengdong/event/application/BillService.java b/server/src/main/java/haengdong/event/application/BillService.java new file mode 100644 index 000000000..09fdd3889 --- /dev/null +++ b/server/src/main/java/haengdong/event/application/BillService.java @@ -0,0 +1,110 @@ +package haengdong.event.application; + +import haengdong.common.exception.HaengdongErrorCode; +import haengdong.common.exception.HaengdongException; +import haengdong.event.application.request.BillAppRequest; +import haengdong.event.application.request.BillDetailsUpdateAppRequest; +import haengdong.event.application.request.BillUpdateAppRequest; +import haengdong.event.application.response.BillDetailsAppResponse; +import haengdong.event.application.response.StepAppResponse; +import haengdong.event.domain.bill.Bill; +import haengdong.event.domain.bill.BillDetail; +import haengdong.event.domain.bill.BillRepository; +import haengdong.event.domain.event.Event; +import haengdong.event.domain.event.EventRepository; +import haengdong.event.domain.event.member.EventMember; +import haengdong.event.domain.event.member.EventMemberRepository; +import haengdong.event.domain.step.Steps; +import java.util.List; +import lombok.RequiredArgsConstructor; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +@RequiredArgsConstructor +@Transactional(readOnly = true) +@Service +public class BillService { + + private final BillRepository billRepository; + private final EventRepository eventRepository; + private final EventMemberRepository eventMemberRepository; + + @Transactional + public void saveBill(String eventToken, BillAppRequest request) { + Event event = getEvent(eventToken); + List memberIds = request.memberIds(); + List eventMembers = memberIds.stream() + .map(this::getMember) + .toList(); + + Bill bill = request.toBill(event, eventMembers); + billRepository.save(bill); + } + + public List findSteps(String token) { + Event event = getEvent(token); + List bills = billRepository.findAllByEvent(event); + + return createStepAppResponses(bills); + } + + private List createStepAppResponses(List bills) { + Steps steps = Steps.of(bills); + return steps.getSteps().stream() + .map(StepAppResponse::of) + .toList(); + } + + @Transactional + public void updateBill(String token, Long billId, BillUpdateAppRequest request) { + Bill bill = getBill(billId); + validateToken(token, bill); + bill.update(request.title(), request.price()); + } + + @Transactional + public void deleteBill(String token, Long billId) { + Bill bill = getBill(billId); + validateToken(token, bill); + billRepository.deleteById(billId); + } + + public BillDetailsAppResponse findBillDetails(String token, Long billId) { + Bill bill = getBill(billId); + validateToken(token, bill); + + List billDetails = bill.getBillDetails(); + return BillDetailsAppResponse.of(billDetails); + } + + @Transactional + public void updateBillDetails(String token, Long billId, BillDetailsUpdateAppRequest request) { + Bill bill = getBill(billId); + validateToken(token, bill); + + List billDetails = request.toBillDetails(bill); + bill.updateDetails(billDetails); + } + + private void validateToken(String token, Bill bill) { + Event event = bill.getEvent(); + if (event.isTokenMismatch(token)) { + throw new HaengdongException(HaengdongErrorCode.BILL_NOT_FOUND); + } + } + + private Event getEvent(String eventToken) { + return eventRepository.findByToken(eventToken) + .orElseThrow(() -> new HaengdongException(HaengdongErrorCode.EVENT_NOT_FOUND)); + } + + private Bill getBill(Long billId) { + return billRepository.findById(billId) + .orElseThrow(() -> new HaengdongException(HaengdongErrorCode.BILL_NOT_FOUND)); + } + + private EventMember getMember(Long memberId) { + return eventMemberRepository.findById(memberId) + .orElseThrow(() -> new HaengdongException(HaengdongErrorCode.MEMBER_NOT_FOUND)); + } +} diff --git a/server/src/main/java/server/haengdong/application/EventImageFacadeService.java b/server/src/main/java/haengdong/event/application/EventImageFacadeService.java similarity index 86% rename from server/src/main/java/server/haengdong/application/EventImageFacadeService.java rename to server/src/main/java/haengdong/event/application/EventImageFacadeService.java index 11a639ca6..d5f5f78f4 100644 --- a/server/src/main/java/server/haengdong/application/EventImageFacadeService.java +++ b/server/src/main/java/haengdong/event/application/EventImageFacadeService.java @@ -1,5 +1,7 @@ -package server.haengdong.application; +package haengdong.event.application; +import haengdong.event.application.response.EventImageAppResponse; +import haengdong.event.application.response.EventImageUrlAppResponse; import java.time.Instant; import java.time.temporal.ChronoUnit; import java.util.List; @@ -13,10 +15,10 @@ import org.springframework.scheduling.annotation.Scheduled; import org.springframework.stereotype.Service; import org.springframework.web.multipart.MultipartFile; -import server.haengdong.application.response.EventImageSaveAppResponse; -import server.haengdong.application.response.ImageInfo; -import server.haengdong.exception.HaengdongErrorCode; -import server.haengdong.exception.HaengdongException; +import haengdong.event.application.response.EventImageSaveAppResponse; +import haengdong.event.application.response.ImageInfo; +import haengdong.common.exception.HaengdongErrorCode; +import haengdong.common.exception.HaengdongException; @RequiredArgsConstructor @Service @@ -125,4 +127,13 @@ private void removeImageNotInRepository(List eventIma .filter(name -> !imageNames.contains(name)) .forEach(imageService::deleteImage); } + + public List findImages(String token) { + List images = eventService.findImages(token); + String baseUrl = imageService.getBaseUrl(); + + return images.stream() + .map(image -> new EventImageUrlAppResponse(image.id(), baseUrl + image.name())) + .toList(); + } } diff --git a/server/src/main/java/haengdong/event/application/EventMemberService.java b/server/src/main/java/haengdong/event/application/EventMemberService.java new file mode 100644 index 000000000..dcc81b79d --- /dev/null +++ b/server/src/main/java/haengdong/event/application/EventMemberService.java @@ -0,0 +1,100 @@ +package haengdong.event.application; + + +import haengdong.common.exception.HaengdongErrorCode; +import haengdong.common.exception.HaengdongException; +import haengdong.event.application.request.MembersSaveAppRequest; +import haengdong.event.application.request.MembersUpdateAppRequest; +import haengdong.event.application.response.MemberAppResponse; +import haengdong.event.application.response.MembersDepositAppResponse; +import haengdong.event.application.response.MembersSaveAppResponse; +import haengdong.event.domain.bill.Bill; +import haengdong.event.domain.bill.BillRepository; +import haengdong.event.domain.event.Event; +import haengdong.event.domain.event.EventRepository; +import haengdong.event.domain.event.member.EventMember; +import haengdong.event.domain.event.member.EventMemberRepository; +import haengdong.event.domain.event.member.EventUniqueMembers; +import haengdong.event.domain.event.member.UpdatedMembers; +import java.util.List; +import lombok.RequiredArgsConstructor; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +@RequiredArgsConstructor +@Transactional(readOnly = true) +@Service +public class EventMemberService { + + private final EventMemberRepository eventMemberRepository; + private final EventRepository eventRepository; + private final BillRepository billRepository; + + @Transactional + public MembersSaveAppResponse saveMembers(String token, MembersSaveAppRequest request) { + Event event = getEvent(token); + EventUniqueMembers eventMembers = request.toEventMembers(event); + validateDuplicateName(eventMembers, event); + + List savedEventMembers = eventMemberRepository.saveAll(eventMembers.getEventMembers()); + return MembersSaveAppResponse.of(savedEventMembers); + } + + private void validateDuplicateName(EventUniqueMembers eventMembers, Event event) { + List foundEventMembers = eventMemberRepository.findAllByEvent(event); + if (eventMembers.containName(foundEventMembers)) { + throw new HaengdongException(HaengdongErrorCode.MEMBER_ALREADY_EXIST); + } + } + + public List getCurrentMembers(String token) { + Event event = getEvent(token); + + return billRepository.findFirstByEventOrderByIdDesc(event) + .map(Bill::getMembers) + .orElseGet(() -> eventMemberRepository.findAllByEvent(event)) + .stream() + .map(MemberAppResponse::of) + .toList(); + } + + public MembersDepositAppResponse findAllMembers(String token) { + Event event = getEvent(token); + List eventMembers = eventMemberRepository.findAllByEvent(event); + return MembersDepositAppResponse.of(eventMembers); + } + + @Transactional + public void updateMembers(String token, MembersUpdateAppRequest request) { + Event event = getEvent(token); + UpdatedMembers updatedMembers = new UpdatedMembers(request.toMembers(event)); + List originEventMembers = eventMemberRepository.findAllByEvent(event); + + updatedMembers.validateUpdatable(originEventMembers); + eventMemberRepository.saveAll(updatedMembers.getMembers()); + } + + @Transactional + public void deleteMember(String token, Long memberId) { + eventMemberRepository.findById(memberId) + .ifPresent(member -> deleteMember(token, member)); + } + + private void deleteMember(String token, EventMember eventMember) { + Event event = eventMember.getEvent(); + if (event.isTokenMismatch(token)) { + throw new HaengdongException(HaengdongErrorCode.MEMBER_NOT_FOUND); + } + + billRepository.findAllByEvent(event).stream() + .filter(bill -> bill.containMember(eventMember)) + .forEach(bill -> bill.removeMemberBillDetail(eventMember)); + billRepository.flush(); + eventMemberRepository.delete(eventMember); + } + + private Event getEvent(String token) { + return eventRepository.findByToken(token) + .orElseThrow(() -> new HaengdongException(HaengdongErrorCode.EVENT_NOT_FOUND)); + } +} diff --git a/server/src/main/java/server/haengdong/application/EventService.java b/server/src/main/java/haengdong/event/application/EventService.java similarity index 53% rename from server/src/main/java/server/haengdong/application/EventService.java rename to server/src/main/java/haengdong/event/application/EventService.java index 1823cf8f1..6633f390f 100644 --- a/server/src/main/java/server/haengdong/application/EventService.java +++ b/server/src/main/java/haengdong/event/application/EventService.java @@ -1,32 +1,36 @@ -package server.haengdong.application; - +package haengdong.event.application; + +import haengdong.common.exception.AuthenticationException; +import haengdong.common.exception.HaengdongErrorCode; +import haengdong.common.exception.HaengdongException; +import haengdong.event.application.request.EventAppRequest; +import haengdong.event.application.request.EventGuestAppRequest; +import haengdong.event.application.request.EventLoginAppRequest; +import haengdong.event.application.request.EventMineAppResponse; +import haengdong.event.application.request.EventUpdateAppRequest; +import haengdong.event.application.response.EventAppResponse; +import haengdong.event.application.response.EventDetailAppResponse; +import haengdong.event.application.response.EventImageAppResponse; +import haengdong.event.application.response.EventImageSaveAppResponse; +import haengdong.event.application.response.MemberBillReportAppResponse; +import haengdong.event.application.response.UserAppResponse; +import haengdong.event.domain.RandomValueProvider; +import haengdong.event.domain.bill.Bill; +import haengdong.event.domain.bill.BillRepository; +import haengdong.event.domain.bill.MemberBillReport; +import haengdong.event.domain.event.Event; +import haengdong.event.domain.event.EventRepository; +import haengdong.event.domain.event.image.EventImage; +import haengdong.event.domain.event.image.EventImageRepository; +import haengdong.event.domain.event.member.EventMember; +import haengdong.event.domain.event.member.EventMemberRepository; +import haengdong.user.application.UserService; import java.time.Instant; import java.util.List; import java.util.Map.Entry; import lombok.RequiredArgsConstructor; -import org.springframework.beans.factory.annotation.Value; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; -import server.haengdong.application.request.EventAppRequest; -import server.haengdong.application.request.EventLoginAppRequest; -import server.haengdong.application.request.EventUpdateAppRequest; -import server.haengdong.application.response.EventAppResponse; -import server.haengdong.application.response.EventDetailAppResponse; -import server.haengdong.application.response.EventImageAppResponse; -import server.haengdong.application.response.EventImageSaveAppResponse; -import server.haengdong.application.response.MemberBillReportAppResponse; -import server.haengdong.domain.RandomValueProvider; -import server.haengdong.domain.bill.Bill; -import server.haengdong.domain.bill.BillRepository; -import server.haengdong.domain.bill.MemberBillReport; -import server.haengdong.domain.event.Event; -import server.haengdong.domain.event.EventImage; -import server.haengdong.domain.event.EventImageRepository; -import server.haengdong.domain.event.EventRepository; -import server.haengdong.domain.member.Member; -import server.haengdong.exception.AuthenticationException; -import server.haengdong.exception.HaengdongErrorCode; -import server.haengdong.exception.HaengdongException; @RequiredArgsConstructor @Transactional(readOnly = true) @@ -39,65 +43,74 @@ public class EventService { private final RandomValueProvider randomValueProvider; private final BillRepository billRepository; private final EventImageRepository eventImageRepository; + private final EventMemberRepository eventMemberRepository; + private final UserService userService; - @Value("${image.base-url}") - private String baseUrl; + @Transactional + public EventAppResponse saveEventGuest(EventGuestAppRequest request) { + Long userId = userService.joinGuest(request.toUserRequest()); + String token = randomValueProvider.createRandomValue(); + Event event = new Event(request.eventName(), userId, token); + eventRepository.save(event); + + eventMemberRepository.save(new EventMember(event, request.nickname())); + return EventAppResponse.of(event); + } @Transactional public EventAppResponse saveEvent(EventAppRequest request) { String token = randomValueProvider.createRandomValue(); - Event event = request.toEvent(token); + Event event = new Event(request.name(), request.userId(), token); eventRepository.save(event); + String nickname = userService.findNicknameById(request.userId()); + eventMemberRepository.save(new EventMember(event, nickname)); + return EventAppResponse.of(event); } public EventDetailAppResponse findEvent(String token) { Event event = getEvent(token); + Long userId = event.getUserId(); + UserAppResponse user = userService.findById(userId); - return EventDetailAppResponse.of(event); + return EventDetailAppResponse.of(event, user); } - public void validatePassword(EventLoginAppRequest request) throws HaengdongException { + public EventAppResponse findByGuestPassword(EventLoginAppRequest request) { Event event = getEvent(request.token()); - if (event.isPasswordMismatch(request.password())) { - throw new AuthenticationException(HaengdongErrorCode.PASSWORD_INVALID); - } + userService.validateUser(event.getUserId(), request.password()); + return EventAppResponse.of(event); } public List getMemberBillReports(String token) { - Event event = eventRepository.findByToken(token) - .orElseThrow(() -> new HaengdongException(HaengdongErrorCode.EVENT_NOT_FOUND)); + Event event = getEvent(token); + List eventMembers = eventMemberRepository.findAllByEvent(event); List bills = billRepository.findAllByEvent(event); - MemberBillReport memberBillReport = MemberBillReport.createByBills(bills); + MemberBillReport memberBillReport = MemberBillReport.create(eventMembers, bills); return memberBillReport.getReports().entrySet().stream() .map(this::createMemberBillReportResponse) .toList(); } - private MemberBillReportAppResponse createMemberBillReportResponse(Entry entry) { - Member member = entry.getKey(); + private MemberBillReportAppResponse createMemberBillReportResponse(Entry entry) { + EventMember eventMember = entry.getKey(); Long price = entry.getValue(); return new MemberBillReportAppResponse( - member.getId(), - member.getName(), - member.isDeposited(), + eventMember.getId(), + eventMember.getName(), + eventMember.isDeposited(), price ); } @Transactional - public void updateEvent(String token, EventUpdateAppRequest request) { + public void updateEventName(String token, EventUpdateAppRequest request) { Event event = getEvent(token); - if (request.isEventNameExist()) { - event.rename(request.eventName()); - } - if (request.isAccountExist()) { - event.changeAccount(request.bankName(), request.accountNumber()); - } + event.rename(request.eventName()); } @Transactional @@ -118,7 +131,7 @@ public List saveImages(String token, List ori private void validateImageCount(List images, Event event) { Long imageCount = eventImageRepository.countByEvent(event); - Long totalImageCount = imageCount + images.size(); + long totalImageCount = imageCount + images.size(); if (totalImageCount > MAX_IMAGE_COUNT) { throw new HaengdongException(HaengdongErrorCode.IMAGE_COUNT_INVALID, totalImageCount); @@ -130,14 +143,10 @@ public List findImages(String token) { return eventImageRepository.findAllByEvent(event) .stream() - .map(image -> new EventImageAppResponse(image.getId(), createUrl(image))) + .map(image -> new EventImageAppResponse(image.getId(), image.getName())) .toList(); } - private String createUrl(EventImage image) { - return baseUrl + image.getName(); - } - @Transactional public String deleteImage(String token, Long imageId) { EventImage eventImage = getEventImage(imageId); @@ -160,6 +169,16 @@ public void deleteImages(String token, List imageIds) { imageIds.forEach(imageId -> deleteImage(token, imageId)); } + public List findImagesDateBefore(Instant date) { + return eventImageRepository.findByCreatedAtAfter(date).stream() + .map(EventImageSaveAppResponse::of) + .toList(); + } + + public boolean existsByTokenAndUserId(String eventToken, Long userId) { + return eventRepository.existsByTokenAndUserId(eventToken, userId); + } + private Event getEvent(String token) { return eventRepository.findByToken(token) .orElseThrow(() -> new HaengdongException(HaengdongErrorCode.EVENT_NOT_FOUND)); @@ -170,9 +189,10 @@ private EventImage getEventImage(Long imageId) { .orElseThrow(() -> new HaengdongException(HaengdongErrorCode.IMAGE_NOT_FOUND)); } - public List findImagesDateBefore(Instant date) { - return eventImageRepository.findByCreatedAtAfter(date).stream() - .map(EventImageSaveAppResponse::of) + public List findByUserId(Long userId) { + return eventRepository.findByUserId(userId).stream() + .map(event -> EventMineAppResponse.of( + event, !eventMemberRepository.existsByEventAndIsDeposited(event, false))) .toList(); } } diff --git a/server/src/main/java/server/haengdong/application/ImageService.java b/server/src/main/java/haengdong/event/application/ImageService.java similarity index 72% rename from server/src/main/java/server/haengdong/application/ImageService.java rename to server/src/main/java/haengdong/event/application/ImageService.java index dd6b39daf..097cfe95e 100644 --- a/server/src/main/java/server/haengdong/application/ImageService.java +++ b/server/src/main/java/haengdong/event/application/ImageService.java @@ -1,21 +1,22 @@ -package server.haengdong.application; +package haengdong.event.application; import static software.amazon.awssdk.core.sync.RequestBody.fromInputStream; +import haengdong.common.exception.HaengdongErrorCode; +import haengdong.common.exception.HaengdongException; +import haengdong.event.application.response.ImageInfo; +import haengdong.event.properties.ImageProperties; import java.io.IOException; import java.io.InputStream; import java.util.List; import java.util.concurrent.CompletableFuture; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; -import org.springframework.beans.factory.annotation.Value; +import org.springframework.boot.context.properties.EnableConfigurationProperties; import org.springframework.retry.annotation.Retryable; import org.springframework.scheduling.annotation.Async; import org.springframework.stereotype.Service; import org.springframework.web.multipart.MultipartFile; -import server.haengdong.application.response.ImageInfo; -import server.haengdong.exception.HaengdongErrorCode; -import server.haengdong.exception.HaengdongException; import software.amazon.awssdk.services.s3.S3Client; import software.amazon.awssdk.services.s3.model.DeleteObjectRequest; import software.amazon.awssdk.services.s3.model.ListObjectsV2Request; @@ -24,15 +25,11 @@ @Slf4j @RequiredArgsConstructor +@EnableConfigurationProperties(ImageProperties.class) @Service public class ImageService { - @Value("${image.bucket}") - private String bucketName; - - @Value("${image.directory}") - private String directoryPath; - + private final ImageProperties imageProperties; private final S3Client s3Client; @Retryable @@ -45,11 +42,11 @@ public void uploadImage(MultipartFile image, String imageName) { } private void uploadImageToStorage(InputStream inputStream, MultipartFile image, String imageName) { - String key = directoryPath + imageName; + String key = imageProperties.directory() + imageName; long contentLength = image.getSize(); PutObjectRequest putObjectRequest = PutObjectRequest.builder() - .bucket(bucketName) + .bucket(imageProperties.bucket()) .key(key) .contentLength(contentLength) .contentType(image.getContentType()) @@ -62,8 +59,8 @@ private void uploadImageToStorage(InputStream inputStream, MultipartFile image, @Retryable public CompletableFuture deleteImage(String imageName) { DeleteObjectRequest deleteObjectRequest = DeleteObjectRequest.builder() - .bucket(bucketName) - .key(directoryPath + imageName) + .bucket(imageProperties.bucket()) + .key(imageProperties.directory() + imageName) .build(); s3Client.deleteObject(deleteObjectRequest); @@ -72,17 +69,21 @@ public CompletableFuture deleteImage(String imageName) { public List findImages() { ListObjectsV2Request request = ListObjectsV2Request.builder() - .bucket(bucketName) - .prefix(directoryPath) + .bucket(imageProperties.bucket()) + .prefix(imageProperties.directory()) .build(); ListObjectsV2Response response = s3Client.listObjectsV2(request); return response.contents().stream() .map(s3Object -> new ImageInfo( - s3Object.key().substring(directoryPath.length()), + s3Object.key().substring(imageProperties.directory().length()), s3Object.lastModified() )) .toList(); } + + public String getBaseUrl() { + return imageProperties.baseUrl(); + } } diff --git a/server/src/main/java/haengdong/event/application/request/BillAppRequest.java b/server/src/main/java/haengdong/event/application/request/BillAppRequest.java new file mode 100644 index 000000000..dbd8cf804 --- /dev/null +++ b/server/src/main/java/haengdong/event/application/request/BillAppRequest.java @@ -0,0 +1,17 @@ +package haengdong.event.application.request; + +import java.util.List; +import haengdong.event.domain.bill.Bill; +import haengdong.event.domain.event.member.EventMember; +import haengdong.event.domain.event.Event; + +public record BillAppRequest( + String title, + Long price, + List memberIds +) { + + public Bill toBill(Event event, List eventMembers) { + return Bill.create(event, title, price, eventMembers); + } +} diff --git a/server/src/main/java/haengdong/event/application/request/BillDetailUpdateAppRequest.java b/server/src/main/java/haengdong/event/application/request/BillDetailUpdateAppRequest.java new file mode 100644 index 000000000..b772eb474 --- /dev/null +++ b/server/src/main/java/haengdong/event/application/request/BillDetailUpdateAppRequest.java @@ -0,0 +1,31 @@ +package haengdong.event.application.request; + +import haengdong.common.exception.HaengdongErrorCode; +import haengdong.common.exception.HaengdongException; +import haengdong.event.domain.bill.Bill; +import haengdong.event.domain.bill.BillDetail; +import haengdong.event.domain.event.member.EventMember; +import java.util.List; + +public record BillDetailUpdateAppRequest( + Long id, + Long price, + boolean isFixed +) { + + public BillDetail toBillDetail(Bill bill) { + List billDetails = bill.getBillDetails(); + + return new BillDetail(bill, findEventMemberById(id, billDetails), price, isFixed); + } + + private EventMember findEventMemberById( + Long id, List billDetails + ) { + return billDetails.stream() + .filter(detail -> detail.isSameId(id)) + .findFirst() + .map(BillDetail::getEventMember) + .orElseThrow(() -> new HaengdongException(HaengdongErrorCode.BILL_DETAIL_NOT_FOUND)); + } +} diff --git a/server/src/main/java/haengdong/event/application/request/BillDetailsUpdateAppRequest.java b/server/src/main/java/haengdong/event/application/request/BillDetailsUpdateAppRequest.java new file mode 100644 index 000000000..cbb5e52d3 --- /dev/null +++ b/server/src/main/java/haengdong/event/application/request/BillDetailsUpdateAppRequest.java @@ -0,0 +1,15 @@ +package haengdong.event.application.request; + +import haengdong.event.domain.bill.Bill; +import haengdong.event.domain.bill.BillDetail; +import java.util.List; + +public record BillDetailsUpdateAppRequest( + List billDetailUpdateAppRequests +) { + public List toBillDetails(Bill bill) { + return billDetailUpdateAppRequests.stream() + .map(request -> request.toBillDetail(bill)) + .toList(); + } +} diff --git a/server/src/main/java/server/haengdong/application/request/BillUpdateAppRequest.java b/server/src/main/java/haengdong/event/application/request/BillUpdateAppRequest.java similarity index 64% rename from server/src/main/java/server/haengdong/application/request/BillUpdateAppRequest.java rename to server/src/main/java/haengdong/event/application/request/BillUpdateAppRequest.java index aa09f2351..cb6f67c26 100644 --- a/server/src/main/java/server/haengdong/application/request/BillUpdateAppRequest.java +++ b/server/src/main/java/haengdong/event/application/request/BillUpdateAppRequest.java @@ -1,4 +1,4 @@ -package server.haengdong.application.request; +package haengdong.event.application.request; public record BillUpdateAppRequest( String title, diff --git a/server/src/main/java/haengdong/event/application/request/EventAppRequest.java b/server/src/main/java/haengdong/event/application/request/EventAppRequest.java new file mode 100644 index 000000000..0d7a6c5a6 --- /dev/null +++ b/server/src/main/java/haengdong/event/application/request/EventAppRequest.java @@ -0,0 +1,10 @@ +package haengdong.event.application.request; + +import haengdong.event.domain.event.Event; + +public record EventAppRequest(String name, Long userId) { + + public Event toEvent(String token) { + return new Event(name, userId, token); + } +} diff --git a/server/src/main/java/haengdong/event/application/request/EventGuestAppRequest.java b/server/src/main/java/haengdong/event/application/request/EventGuestAppRequest.java new file mode 100644 index 000000000..60190d943 --- /dev/null +++ b/server/src/main/java/haengdong/event/application/request/EventGuestAppRequest.java @@ -0,0 +1,13 @@ +package haengdong.event.application.request; + +import haengdong.user.application.request.UserGuestSaveAppRequest; + +public record EventGuestAppRequest( + String eventName, + String nickname, + String password +) { + public UserGuestSaveAppRequest toUserRequest() { + return new UserGuestSaveAppRequest(nickname, password); + } +} diff --git a/server/src/main/java/server/haengdong/application/request/EventLoginAppRequest.java b/server/src/main/java/haengdong/event/application/request/EventLoginAppRequest.java similarity index 60% rename from server/src/main/java/server/haengdong/application/request/EventLoginAppRequest.java rename to server/src/main/java/haengdong/event/application/request/EventLoginAppRequest.java index 947b5ef39..3a3256266 100644 --- a/server/src/main/java/server/haengdong/application/request/EventLoginAppRequest.java +++ b/server/src/main/java/haengdong/event/application/request/EventLoginAppRequest.java @@ -1,4 +1,4 @@ -package server.haengdong.application.request; +package haengdong.event.application.request; public record EventLoginAppRequest(String token, String password) { } diff --git a/server/src/main/java/haengdong/event/application/request/EventMineAppResponse.java b/server/src/main/java/haengdong/event/application/request/EventMineAppResponse.java new file mode 100644 index 000000000..b714b9576 --- /dev/null +++ b/server/src/main/java/haengdong/event/application/request/EventMineAppResponse.java @@ -0,0 +1,16 @@ +package haengdong.event.application.request; + +import haengdong.event.domain.event.Event; +import java.time.LocalDateTime; +import java.time.ZoneId; + +public record EventMineAppResponse( + String eventId, + String eventName, + boolean isFinished, + LocalDateTime createdAt +) { + public static EventMineAppResponse of(Event event, boolean isFinished) { + return new EventMineAppResponse(event.getToken(), event.getName(), isFinished, LocalDateTime.ofInstant(event.getCreatedAt(), ZoneId.of("Asia/Seoul")) ); + } +} diff --git a/server/src/main/java/haengdong/event/application/request/EventUpdateAppRequest.java b/server/src/main/java/haengdong/event/application/request/EventUpdateAppRequest.java new file mode 100644 index 000000000..2800a380c --- /dev/null +++ b/server/src/main/java/haengdong/event/application/request/EventUpdateAppRequest.java @@ -0,0 +1,6 @@ +package haengdong.event.application.request; + +public record EventUpdateAppRequest( + String eventName +) { +} diff --git a/server/src/main/java/server/haengdong/application/request/MemberNameUpdateAppRequest.java b/server/src/main/java/haengdong/event/application/request/MemberNameUpdateAppRequest.java similarity index 65% rename from server/src/main/java/server/haengdong/application/request/MemberNameUpdateAppRequest.java rename to server/src/main/java/haengdong/event/application/request/MemberNameUpdateAppRequest.java index b36d71cc1..55e6199c8 100644 --- a/server/src/main/java/server/haengdong/application/request/MemberNameUpdateAppRequest.java +++ b/server/src/main/java/haengdong/event/application/request/MemberNameUpdateAppRequest.java @@ -1,4 +1,4 @@ -package server.haengdong.application.request; +package haengdong.event.application.request; public record MemberNameUpdateAppRequest( Long id, diff --git a/server/src/main/java/server/haengdong/application/request/MemberNamesUpdateAppRequest.java b/server/src/main/java/haengdong/event/application/request/MemberNamesUpdateAppRequest.java similarity index 72% rename from server/src/main/java/server/haengdong/application/request/MemberNamesUpdateAppRequest.java rename to server/src/main/java/haengdong/event/application/request/MemberNamesUpdateAppRequest.java index cd0c00544..184466ff9 100644 --- a/server/src/main/java/server/haengdong/application/request/MemberNamesUpdateAppRequest.java +++ b/server/src/main/java/haengdong/event/application/request/MemberNamesUpdateAppRequest.java @@ -1,4 +1,4 @@ -package server.haengdong.application.request; +package haengdong.event.application.request; import java.util.List; diff --git a/server/src/main/java/server/haengdong/application/request/MemberSaveAppRequest.java b/server/src/main/java/haengdong/event/application/request/MemberSaveAppRequest.java similarity index 53% rename from server/src/main/java/server/haengdong/application/request/MemberSaveAppRequest.java rename to server/src/main/java/haengdong/event/application/request/MemberSaveAppRequest.java index 45dc234e3..308453982 100644 --- a/server/src/main/java/server/haengdong/application/request/MemberSaveAppRequest.java +++ b/server/src/main/java/haengdong/event/application/request/MemberSaveAppRequest.java @@ -1,4 +1,4 @@ -package server.haengdong.application.request; +package haengdong.event.application.request; public record MemberSaveAppRequest(String name) { } diff --git a/server/src/main/java/haengdong/event/application/request/MemberUpdateAppRequest.java b/server/src/main/java/haengdong/event/application/request/MemberUpdateAppRequest.java new file mode 100644 index 000000000..c3b23772e --- /dev/null +++ b/server/src/main/java/haengdong/event/application/request/MemberUpdateAppRequest.java @@ -0,0 +1,16 @@ +package haengdong.event.application.request; + + +import haengdong.event.domain.event.member.EventMember; +import haengdong.event.domain.event.Event; + +public record MemberUpdateAppRequest( + Long id, + String name, + boolean isDeposited +) { + + public EventMember toMember(Event event) { + return new EventMember(id, event, name, isDeposited); + } +} diff --git a/server/src/main/java/haengdong/event/application/request/MembersSaveAppRequest.java b/server/src/main/java/haengdong/event/application/request/MembersSaveAppRequest.java new file mode 100644 index 000000000..32b1df37f --- /dev/null +++ b/server/src/main/java/haengdong/event/application/request/MembersSaveAppRequest.java @@ -0,0 +1,18 @@ +package haengdong.event.application.request; + +import haengdong.event.domain.event.Event; +import haengdong.event.domain.event.member.EventMember; +import haengdong.event.domain.event.member.EventUniqueMembers; +import java.util.List; + +public record MembersSaveAppRequest( + List members +) { + public EventUniqueMembers toEventMembers(Event event) { + List eventMembers = members.stream() + .map(member -> new EventMember(event, member.name())) + .toList(); + + return new EventUniqueMembers(eventMembers); + } +} diff --git a/server/src/main/java/server/haengdong/application/request/MembersUpdateAppRequest.java b/server/src/main/java/haengdong/event/application/request/MembersUpdateAppRequest.java similarity index 54% rename from server/src/main/java/server/haengdong/application/request/MembersUpdateAppRequest.java rename to server/src/main/java/haengdong/event/application/request/MembersUpdateAppRequest.java index aa3253504..3a5fdb185 100644 --- a/server/src/main/java/server/haengdong/application/request/MembersUpdateAppRequest.java +++ b/server/src/main/java/haengdong/event/application/request/MembersUpdateAppRequest.java @@ -1,12 +1,12 @@ -package server.haengdong.application.request; +package haengdong.event.application.request; import java.util.List; -import server.haengdong.domain.event.Event; -import server.haengdong.domain.member.Member; +import haengdong.event.domain.event.Event; +import haengdong.event.domain.event.member.EventMember; public record MembersUpdateAppRequest(List members) { - public List toMembers(Event event) { + public List toMembers(Event event) { return members.stream() .map(memberRequest -> memberRequest.toMember(event)) .toList(); diff --git a/server/src/main/java/server/haengdong/application/response/BillAppResponse.java b/server/src/main/java/haengdong/event/application/response/BillAppResponse.java similarity index 75% rename from server/src/main/java/server/haengdong/application/response/BillAppResponse.java rename to server/src/main/java/haengdong/event/application/response/BillAppResponse.java index 6ee68935c..95ab9ebce 100644 --- a/server/src/main/java/server/haengdong/application/response/BillAppResponse.java +++ b/server/src/main/java/haengdong/event/application/response/BillAppResponse.java @@ -1,6 +1,6 @@ -package server.haengdong.application.response; +package haengdong.event.application.response; -import server.haengdong.domain.bill.Bill; +import haengdong.event.domain.bill.Bill; public record BillAppResponse( Long id, diff --git a/server/src/main/java/server/haengdong/application/response/BillDetailAppResponse.java b/server/src/main/java/haengdong/event/application/response/BillDetailAppResponse.java similarity index 71% rename from server/src/main/java/server/haengdong/application/response/BillDetailAppResponse.java rename to server/src/main/java/haengdong/event/application/response/BillDetailAppResponse.java index 6618135cb..31c20865b 100644 --- a/server/src/main/java/server/haengdong/application/response/BillDetailAppResponse.java +++ b/server/src/main/java/haengdong/event/application/response/BillDetailAppResponse.java @@ -1,6 +1,6 @@ -package server.haengdong.application.response; +package haengdong.event.application.response; -import server.haengdong.domain.bill.BillDetail; +import haengdong.event.domain.bill.BillDetail; public record BillDetailAppResponse( Long id, @@ -12,7 +12,7 @@ public record BillDetailAppResponse( public static BillDetailAppResponse of(BillDetail billDetail) { return new BillDetailAppResponse( billDetail.getId(), - billDetail.getMember().getName(), + billDetail.getEventMember().getName(), billDetail.getPrice(), billDetail.isFixed() ); diff --git a/server/src/main/java/server/haengdong/application/response/BillDetailsAppResponse.java b/server/src/main/java/haengdong/event/application/response/BillDetailsAppResponse.java similarity index 81% rename from server/src/main/java/server/haengdong/application/response/BillDetailsAppResponse.java rename to server/src/main/java/haengdong/event/application/response/BillDetailsAppResponse.java index 3618e0d08..8367aa1af 100644 --- a/server/src/main/java/server/haengdong/application/response/BillDetailsAppResponse.java +++ b/server/src/main/java/haengdong/event/application/response/BillDetailsAppResponse.java @@ -1,8 +1,8 @@ -package server.haengdong.application.response; +package haengdong.event.application.response; import java.util.List; import java.util.stream.Collectors; -import server.haengdong.domain.bill.BillDetail; +import haengdong.event.domain.bill.BillDetail; public record BillDetailsAppResponse(List billDetails) { diff --git a/server/src/main/java/haengdong/event/application/response/EventAppResponse.java b/server/src/main/java/haengdong/event/application/response/EventAppResponse.java new file mode 100644 index 000000000..fd26f660b --- /dev/null +++ b/server/src/main/java/haengdong/event/application/response/EventAppResponse.java @@ -0,0 +1,13 @@ +package haengdong.event.application.response; + +import haengdong.event.domain.event.Event; + +public record EventAppResponse( + String token, + Long userId +) { + + public static EventAppResponse of(Event event) { + return new EventAppResponse(event.getToken(), event.getUserId()); + } +} diff --git a/server/src/main/java/haengdong/event/application/response/EventDetailAppResponse.java b/server/src/main/java/haengdong/event/application/response/EventDetailAppResponse.java new file mode 100644 index 000000000..7c275d349 --- /dev/null +++ b/server/src/main/java/haengdong/event/application/response/EventDetailAppResponse.java @@ -0,0 +1,15 @@ +package haengdong.event.application.response; + +import haengdong.event.domain.event.Event; + +public record EventDetailAppResponse( + String eventName, + String bankName, + String accountNumber, + Boolean createdByGuest +) { + + public static EventDetailAppResponse of(Event event, UserAppResponse user) { + return new EventDetailAppResponse(event.getName(), user.bankName(), user.accountNumber(), user.isGuest()); + } +} diff --git a/server/src/main/java/haengdong/event/application/response/EventImageAppResponse.java b/server/src/main/java/haengdong/event/application/response/EventImageAppResponse.java new file mode 100644 index 000000000..0261ad7bd --- /dev/null +++ b/server/src/main/java/haengdong/event/application/response/EventImageAppResponse.java @@ -0,0 +1,7 @@ +package haengdong.event.application.response; + +public record EventImageAppResponse( + Long id, + String name +) { +} diff --git a/server/src/main/java/server/haengdong/application/response/EventImageSaveAppResponse.java b/server/src/main/java/haengdong/event/application/response/EventImageSaveAppResponse.java similarity index 71% rename from server/src/main/java/server/haengdong/application/response/EventImageSaveAppResponse.java rename to server/src/main/java/haengdong/event/application/response/EventImageSaveAppResponse.java index e1da79de3..985822aca 100644 --- a/server/src/main/java/server/haengdong/application/response/EventImageSaveAppResponse.java +++ b/server/src/main/java/haengdong/event/application/response/EventImageSaveAppResponse.java @@ -1,6 +1,6 @@ -package server.haengdong.application.response; +package haengdong.event.application.response; -import server.haengdong.domain.event.EventImage; +import haengdong.event.domain.event.image.EventImage; public record EventImageSaveAppResponse( Long id, diff --git a/server/src/main/java/haengdong/event/application/response/EventImageUrlAppResponse.java b/server/src/main/java/haengdong/event/application/response/EventImageUrlAppResponse.java new file mode 100644 index 000000000..75870d33b --- /dev/null +++ b/server/src/main/java/haengdong/event/application/response/EventImageUrlAppResponse.java @@ -0,0 +1,7 @@ +package haengdong.event.application.response; + +public record EventImageUrlAppResponse( + Long id, + String url +) { +} diff --git a/server/src/main/java/server/haengdong/application/response/ImageInfo.java b/server/src/main/java/haengdong/event/application/response/ImageInfo.java similarity index 69% rename from server/src/main/java/server/haengdong/application/response/ImageInfo.java rename to server/src/main/java/haengdong/event/application/response/ImageInfo.java index 92deb1f72..73fc06f75 100644 --- a/server/src/main/java/server/haengdong/application/response/ImageInfo.java +++ b/server/src/main/java/haengdong/event/application/response/ImageInfo.java @@ -1,4 +1,4 @@ -package server.haengdong.application.response; +package haengdong.event.application.response; import java.time.Instant; diff --git a/server/src/main/java/haengdong/event/application/response/LastBillMemberAppResponse.java b/server/src/main/java/haengdong/event/application/response/LastBillMemberAppResponse.java new file mode 100644 index 000000000..ba803c58e --- /dev/null +++ b/server/src/main/java/haengdong/event/application/response/LastBillMemberAppResponse.java @@ -0,0 +1,10 @@ +package haengdong.event.application.response; + +import haengdong.event.domain.event.member.EventMember; + +public record LastBillMemberAppResponse(Long id, String name) { + + public static LastBillMemberAppResponse of(EventMember eventMember) { + return new LastBillMemberAppResponse(eventMember.getId(), eventMember.getName()); + } +} diff --git a/server/src/main/java/haengdong/event/application/response/MemberAppResponse.java b/server/src/main/java/haengdong/event/application/response/MemberAppResponse.java new file mode 100644 index 000000000..711f5274c --- /dev/null +++ b/server/src/main/java/haengdong/event/application/response/MemberAppResponse.java @@ -0,0 +1,13 @@ +package haengdong.event.application.response; + +import haengdong.event.domain.event.member.EventMember; + +public record MemberAppResponse( + Long id, + String name +) { + + public static MemberAppResponse of(EventMember eventMember) { + return new MemberAppResponse(eventMember.getId(), eventMember.getName()); + } +} diff --git a/server/src/main/java/server/haengdong/application/response/MemberBillReportAppResponse.java b/server/src/main/java/haengdong/event/application/response/MemberBillReportAppResponse.java similarity index 75% rename from server/src/main/java/server/haengdong/application/response/MemberBillReportAppResponse.java rename to server/src/main/java/haengdong/event/application/response/MemberBillReportAppResponse.java index 875578fbc..66dbdad53 100644 --- a/server/src/main/java/server/haengdong/application/response/MemberBillReportAppResponse.java +++ b/server/src/main/java/haengdong/event/application/response/MemberBillReportAppResponse.java @@ -1,4 +1,4 @@ -package server.haengdong.application.response; +package haengdong.event.application.response; public record MemberBillReportAppResponse( Long memberId, diff --git a/server/src/main/java/haengdong/event/application/response/MemberDepositAppResponse.java b/server/src/main/java/haengdong/event/application/response/MemberDepositAppResponse.java new file mode 100644 index 000000000..a9db0c6c6 --- /dev/null +++ b/server/src/main/java/haengdong/event/application/response/MemberDepositAppResponse.java @@ -0,0 +1,14 @@ +package haengdong.event.application.response; + +import haengdong.event.domain.event.member.EventMember; + +public record MemberDepositAppResponse( + Long id, + String name, + boolean isDeposited +) { + + public static MemberDepositAppResponse of(EventMember eventMember) { + return new MemberDepositAppResponse(eventMember.getId(), eventMember.getName(), eventMember.isDeposited()); + } +} diff --git a/server/src/main/java/haengdong/event/application/response/MemberSaveAppResponse.java b/server/src/main/java/haengdong/event/application/response/MemberSaveAppResponse.java new file mode 100644 index 000000000..bd1c2a6f3 --- /dev/null +++ b/server/src/main/java/haengdong/event/application/response/MemberSaveAppResponse.java @@ -0,0 +1,13 @@ +package haengdong.event.application.response; + +import haengdong.event.domain.event.member.EventMember; + +public record MemberSaveAppResponse( + Long id, + String name +) { + + public static MemberSaveAppResponse of(EventMember eventMember) { + return new MemberSaveAppResponse(eventMember.getId(), eventMember.getName()); + } +} diff --git a/server/src/main/java/haengdong/event/application/response/MembersDepositAppResponse.java b/server/src/main/java/haengdong/event/application/response/MembersDepositAppResponse.java new file mode 100644 index 000000000..1239a300d --- /dev/null +++ b/server/src/main/java/haengdong/event/application/response/MembersDepositAppResponse.java @@ -0,0 +1,15 @@ +package haengdong.event.application.response; + +import java.util.List; +import haengdong.event.domain.event.member.EventMember; + +public record MembersDepositAppResponse( + List members +) { + + public static MembersDepositAppResponse of(List eventMembers) { + return new MembersDepositAppResponse(eventMembers.stream() + .map(MemberDepositAppResponse::of) + .toList()); + } +} diff --git a/server/src/main/java/server/haengdong/application/response/MembersSaveAppResponse.java b/server/src/main/java/haengdong/event/application/response/MembersSaveAppResponse.java similarity index 54% rename from server/src/main/java/server/haengdong/application/response/MembersSaveAppResponse.java rename to server/src/main/java/haengdong/event/application/response/MembersSaveAppResponse.java index c81fe0996..c91000add 100644 --- a/server/src/main/java/server/haengdong/application/response/MembersSaveAppResponse.java +++ b/server/src/main/java/haengdong/event/application/response/MembersSaveAppResponse.java @@ -1,15 +1,15 @@ -package server.haengdong.application.response; +package haengdong.event.application.response; import java.util.List; -import server.haengdong.domain.member.Member; +import haengdong.event.domain.event.member.EventMember; public record MembersSaveAppResponse( List members ) { - public static MembersSaveAppResponse of(List members) { + public static MembersSaveAppResponse of(List eventMembers) { return new MembersSaveAppResponse( - members.stream() + eventMembers.stream() .map(MemberSaveAppResponse::of) .toList() ); diff --git a/server/src/main/java/server/haengdong/application/response/StepAppResponse.java b/server/src/main/java/haengdong/event/application/response/StepAppResponse.java similarity index 86% rename from server/src/main/java/server/haengdong/application/response/StepAppResponse.java rename to server/src/main/java/haengdong/event/application/response/StepAppResponse.java index 57ca1860c..cc919cafe 100644 --- a/server/src/main/java/server/haengdong/application/response/StepAppResponse.java +++ b/server/src/main/java/haengdong/event/application/response/StepAppResponse.java @@ -1,7 +1,7 @@ -package server.haengdong.application.response; +package haengdong.event.application.response; import java.util.List; -import server.haengdong.domain.step.Step; +import haengdong.event.domain.step.Step; public record StepAppResponse( List bills, diff --git a/server/src/main/java/haengdong/event/application/response/UserAppResponse.java b/server/src/main/java/haengdong/event/application/response/UserAppResponse.java new file mode 100644 index 000000000..a29f765a1 --- /dev/null +++ b/server/src/main/java/haengdong/event/application/response/UserAppResponse.java @@ -0,0 +1,13 @@ +package haengdong.event.application.response; + +import haengdong.user.domain.User; + +public record UserAppResponse( + String bankName, + String accountNumber, + Boolean isGuest +) { + public static UserAppResponse of(User user) { + return new UserAppResponse(user.getBank(), user.getAccountNumber(), user.isGuest()); + } +} diff --git a/server/src/main/java/haengdong/event/config/S3Config.java b/server/src/main/java/haengdong/event/config/S3Config.java new file mode 100644 index 000000000..2a5bd91e6 --- /dev/null +++ b/server/src/main/java/haengdong/event/config/S3Config.java @@ -0,0 +1,44 @@ +package haengdong.event.config; + +import jakarta.annotation.PreDestroy; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; +import java.util.concurrent.TimeUnit; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import software.amazon.awssdk.regions.Region; +import software.amazon.awssdk.services.s3.S3Client; + +@Configuration +public class S3Config { + + private static final int THREAD_POOL_SIZE = 10; + private static final int LIFE_CYCLE_SHUTDOWN_TIME_SEC = 10; + + private final ExecutorService executorService = Executors.newFixedThreadPool(THREAD_POOL_SIZE); + + @Bean + public S3Client s3Client() { + return S3Client.builder() + .region(Region.AP_NORTHEAST_2) + .build(); + } + + @Bean + public ExecutorService executorService() { + return executorService; + } + + @PreDestroy + public void shutdown() { + executorService.shutdown(); + try { + if (!executorService.awaitTermination(LIFE_CYCLE_SHUTDOWN_TIME_SEC, TimeUnit.SECONDS)) { + executorService.shutdownNow(); + } + } catch (InterruptedException e) { + executorService.shutdownNow(); + Thread.currentThread().interrupt(); + } + } +} diff --git a/server/src/main/java/server/haengdong/domain/RandomValueProvider.java b/server/src/main/java/haengdong/event/domain/RandomValueProvider.java similarity index 75% rename from server/src/main/java/server/haengdong/domain/RandomValueProvider.java rename to server/src/main/java/haengdong/event/domain/RandomValueProvider.java index 9f05f62a2..b8ca2e5b5 100644 --- a/server/src/main/java/server/haengdong/domain/RandomValueProvider.java +++ b/server/src/main/java/haengdong/event/domain/RandomValueProvider.java @@ -1,4 +1,4 @@ -package server.haengdong.domain; +package haengdong.event.domain; import java.util.UUID; diff --git a/server/src/main/java/server/haengdong/domain/bill/Bill.java b/server/src/main/java/haengdong/event/domain/bill/Bill.java similarity index 63% rename from server/src/main/java/server/haengdong/domain/bill/Bill.java rename to server/src/main/java/haengdong/event/domain/bill/Bill.java index 747a526e0..fddd9e19e 100644 --- a/server/src/main/java/server/haengdong/domain/bill/Bill.java +++ b/server/src/main/java/haengdong/event/domain/bill/Bill.java @@ -1,5 +1,10 @@ -package server.haengdong.domain.bill; +package haengdong.event.domain.bill; +import haengdong.common.domain.BaseEntity; +import haengdong.common.exception.HaengdongErrorCode; +import haengdong.common.exception.HaengdongException; +import haengdong.event.domain.event.Event; +import haengdong.event.domain.event.member.EventMember; import jakarta.persistence.CascadeType; import jakarta.persistence.Column; import jakarta.persistence.Entity; @@ -13,17 +18,11 @@ import java.util.ArrayList; import java.util.Iterator; import java.util.List; -import java.util.Set; import java.util.stream.Collectors; import java.util.stream.Stream; import lombok.AccessLevel; import lombok.Getter; import lombok.NoArgsConstructor; -import server.haengdong.domain.BaseEntity; -import server.haengdong.domain.member.Member; -import server.haengdong.domain.event.Event; -import server.haengdong.exception.HaengdongErrorCode; -import server.haengdong.exception.HaengdongException; @Getter @NoArgsConstructor(access = AccessLevel.PROTECTED) @@ -73,18 +72,18 @@ private void validatePrice(Long price) { } } - public static Bill create(Event event, String title, Long price, List members) { + public static Bill create(Event event, String title, Long price, List eventMembers) { Bill bill = new Bill(event, title, price); - bill.resetBillDetails(members); + bill.resetBillDetails(eventMembers); return bill; } - public void resetBillDetails(List members) { + public void resetBillDetails(List eventMembers) { this.billDetails.clear(); - Iterator priceIterator = distributePrice(members.size()).iterator(); + Iterator priceIterator = distributePrice(eventMembers.size()).iterator(); - for (Member member : members) { - BillDetail billDetail = new BillDetail(this, member, priceIterator.next(), false); + for (EventMember eventMember : eventMembers) { + BillDetail billDetail = new BillDetail(this, eventMember, priceIterator.next(), false); this.billDetails.add(billDetail); } } @@ -112,9 +111,9 @@ private List distributePrice(int memberCount) { return results; } - public void removeMemberBillDetail(Member member) { + public void removeMemberBillDetail(EventMember eventMember) { BillDetail foundBillDetail = billDetails.stream() - .filter(billDetail -> billDetail.isMember(member)) + .filter(billDetail -> billDetail.isMember(eventMember)) .findFirst() .orElseThrow(() -> new HaengdongException(HaengdongErrorCode.MEMBER_NOT_FOUND)); @@ -130,20 +129,43 @@ public void update(String title, Long price) { resetBillDetails(); } - public boolean containMember(Member member) { - return billDetails.stream() - .anyMatch(billDetail -> billDetail.isMember(member)); + public void updateDetails(List billDetails) { + validateBillDetailSize(billDetails); + validateTotalPrice(billDetails); + this.billDetails.clear(); + this.billDetails.addAll(billDetails); + } + + private void validateBillDetailSize(List billDetails) { + List ids = billDetails.stream() + .map(billDetail -> billDetail.getEventMember().getId()) + .distinct() + .toList(); + if (this.billDetails.size() != ids.size()) { + throw new HaengdongException(HaengdongErrorCode.BILL_DETAIL_NOT_FOUND); + } } - public boolean isSameMembers(Bill other) { - Set members = Set.copyOf(this.getMembers()); - Set otherMembers = Set.copyOf(other.getMembers()); + private void validateTotalPrice(List billDetails) { + Long requestsPriceSum = calculateUpdatePriceSum(billDetails); + if (isNotSamePrice(requestsPriceSum)) { + throw new HaengdongException(HaengdongErrorCode.BILL_PRICE_NOT_MATCHED); + } + } + + private Long calculateUpdatePriceSum(List billDetails) { + return billDetails.stream() + .map(BillDetail::getPrice) + .reduce(0L, Long::sum); + } - return members.equals(otherMembers); + public boolean containMember(EventMember eventMember) { + return billDetails.stream() + .anyMatch(billDetail -> billDetail.isMember(eventMember)); } - public boolean isSamePrice(Long price) { - return this.price.equals(price); + private boolean isNotSamePrice(Long price) { + return !this.price.equals(price); } public boolean isFixed() { @@ -151,9 +173,9 @@ public boolean isFixed() { .anyMatch(BillDetail::isFixed); } - public List getMembers() { + public List getMembers() { return billDetails.stream() - .map(BillDetail::getMember) + .map(BillDetail::getEventMember) .toList(); } } diff --git a/server/src/main/java/server/haengdong/domain/bill/BillDetail.java b/server/src/main/java/haengdong/event/domain/bill/BillDetail.java similarity index 75% rename from server/src/main/java/server/haengdong/domain/bill/BillDetail.java rename to server/src/main/java/haengdong/event/domain/bill/BillDetail.java index 8a754b2b9..3177f9cbd 100644 --- a/server/src/main/java/server/haengdong/domain/bill/BillDetail.java +++ b/server/src/main/java/haengdong/event/domain/bill/BillDetail.java @@ -1,4 +1,4 @@ -package server.haengdong.domain.bill; +package haengdong.event.domain.bill; import jakarta.persistence.Column; import jakarta.persistence.Entity; @@ -11,8 +11,8 @@ import lombok.AccessLevel; import lombok.Getter; import lombok.NoArgsConstructor; -import server.haengdong.domain.BaseEntity; -import server.haengdong.domain.member.Member; +import haengdong.common.domain.BaseEntity; +import haengdong.event.domain.event.member.EventMember; @Getter @NoArgsConstructor(access = AccessLevel.PROTECTED) @@ -29,7 +29,7 @@ public class BillDetail extends BaseEntity { @JoinColumn(name = "member_id", nullable = false) @ManyToOne(fetch = FetchType.LAZY) - private Member member; + private EventMember eventMember; @Column(nullable = false) private Long price; @@ -37,9 +37,9 @@ public class BillDetail extends BaseEntity { @Column(nullable = false) private boolean isFixed; - public BillDetail(Bill bill, Member member, Long price, boolean isFixed) { + public BillDetail(Bill bill, EventMember eventMember, Long price, boolean isFixed) { this.bill = bill; - this.member = member; + this.eventMember = eventMember; this.price = price; this.isFixed = isFixed; } @@ -56,7 +56,7 @@ public boolean isSameId(Long id) { return this.id.equals(id); } - public boolean isMember(Member member) { - return this.member.equals(member); + public boolean isMember(EventMember eventMember) { + return this.eventMember.equals(eventMember); } } diff --git a/server/src/main/java/server/haengdong/domain/bill/BillRepository.java b/server/src/main/java/haengdong/event/domain/bill/BillRepository.java similarity index 82% rename from server/src/main/java/server/haengdong/domain/bill/BillRepository.java rename to server/src/main/java/haengdong/event/domain/bill/BillRepository.java index 23efe487c..80b8df959 100644 --- a/server/src/main/java/server/haengdong/domain/bill/BillRepository.java +++ b/server/src/main/java/haengdong/event/domain/bill/BillRepository.java @@ -1,11 +1,11 @@ -package server.haengdong.domain.bill; +package haengdong.event.domain.bill; import java.util.List; import java.util.Optional; import org.springframework.data.jpa.repository.JpaRepository; import org.springframework.data.jpa.repository.Query; import org.springframework.stereotype.Repository; -import server.haengdong.domain.event.Event; +import haengdong.event.domain.event.Event; @Repository public interface BillRepository extends JpaRepository { @@ -14,7 +14,7 @@ public interface BillRepository extends JpaRepository { select b from Bill b join fetch b.billDetails bd - join fetch bd.member + join fetch bd.eventMember where b.event = :event """) List findAllByEvent(Event event); diff --git a/server/src/main/java/haengdong/event/domain/bill/MemberBillReport.java b/server/src/main/java/haengdong/event/domain/bill/MemberBillReport.java new file mode 100644 index 000000000..580595bfa --- /dev/null +++ b/server/src/main/java/haengdong/event/domain/bill/MemberBillReport.java @@ -0,0 +1,32 @@ +package haengdong.event.domain.bill; + +import static java.util.stream.Collectors.toMap; + +import haengdong.event.domain.event.member.EventMember; +import java.util.List; +import java.util.Map; +import lombok.Getter; + +@Getter +public class MemberBillReport { + + private final Map reports; + + private MemberBillReport(Map reports) { + this.reports = reports; + } + + public static MemberBillReport create(List eventMembers, List bills) { + Map reports = bills.stream() + .flatMap(bill -> bill.getBillDetails().stream()) + .collect(toMap( + BillDetail::getEventMember, + BillDetail::getPrice, + Long::sum, + () -> eventMembers.stream() + .collect(toMap(member -> member, member -> 0L)) + )); + + return new MemberBillReport(reports); + } +} diff --git a/server/src/main/java/server/haengdong/domain/event/Event.java b/server/src/main/java/haengdong/event/domain/event/Event.java similarity index 52% rename from server/src/main/java/server/haengdong/domain/event/Event.java rename to server/src/main/java/haengdong/event/domain/event/Event.java index a7cc00fb3..8fb3e9c88 100644 --- a/server/src/main/java/server/haengdong/domain/event/Event.java +++ b/server/src/main/java/haengdong/event/domain/event/Event.java @@ -1,5 +1,8 @@ -package server.haengdong.domain.event; +package haengdong.event.domain.event; +import haengdong.common.domain.BaseEntity; +import haengdong.common.exception.HaengdongErrorCode; +import haengdong.common.exception.HaengdongException; import jakarta.persistence.AttributeOverride; import jakarta.persistence.Column; import jakarta.persistence.Embedded; @@ -7,14 +10,9 @@ import jakarta.persistence.GeneratedValue; import jakarta.persistence.GenerationType; import jakarta.persistence.Id; -import java.time.Instant; -import java.util.Arrays; import lombok.AccessLevel; import lombok.Getter; import lombok.NoArgsConstructor; -import server.haengdong.domain.BaseEntity; -import server.haengdong.exception.HaengdongErrorCode; -import server.haengdong.exception.HaengdongException; @Getter @NoArgsConstructor(access = AccessLevel.PROTECTED) @@ -23,8 +21,6 @@ public class Event extends BaseEntity { private static final int MIN_NAME_LENGTH = 1; private static final int MAX_NAME_LENGTH = 20; - private static final int MIN_ACCOUNT_NUMBER_LENGTH = 8; - private static final int MAX_ACCOUNT_NUMBER_LENGTH = 30; private static final String SPACES = " "; @Id @@ -35,22 +31,28 @@ public class Event extends BaseEntity { private String name; @Embedded - @AttributeOverride(name = "value", column = @Column(name = "password", nullable = false)) + @AttributeOverride(name = "value", column = @Column(name = "password")) private Password password; @Column(nullable = false, unique = true) private String token; - @Column(length = MAX_ACCOUNT_NUMBER_LENGTH) - private String account; + @Column(nullable = false) + private Long userId; - - public Event(String name, String password, String token) { + private Event(String name, String password, String token) { validateName(name); this.name = name; this.password = new Password(password); this.token = token; - this.account = ""; + this.userId = 0L; + } + + public Event(String name, Long userId, String token) { + validateName(name); + this.name = name; + this.userId = userId; + this.token = token; } private void validateName(String name) { @@ -80,38 +82,4 @@ public void rename(String name) { validateName(name); this.name = name; } - - public void changeAccount(String bankName, String accountNumber) { - validateBankName(bankName); - validateAccountNumber(accountNumber); - this.account = bankName + " " + accountNumber; - } - - private void validateBankName(String bankName) { - Bank.isExists(bankName); - } - - private void validateAccountNumber(String accountNumber) { - int accountLength = accountNumber.trim().length(); - if (accountLength < MIN_ACCOUNT_NUMBER_LENGTH || MAX_ACCOUNT_NUMBER_LENGTH < accountLength) { - throw new HaengdongException( - HaengdongErrorCode.ACCOUNT_LENGTH_INVALID, MIN_ACCOUNT_NUMBER_LENGTH, MAX_ACCOUNT_NUMBER_LENGTH); - } - } - - public String getBankName() { - String[] bankNameAndAccountNumber = account.split(" "); - if (bankNameAndAccountNumber.length > 0) { - return bankNameAndAccountNumber[0]; - } - return ""; - } - - public String getAccountNumber() { - String[] bankNameAndAccountNumber = account.split(" "); - if (bankNameAndAccountNumber.length > 1) { - return String.join(" ", Arrays.copyOfRange(bankNameAndAccountNumber, 1, bankNameAndAccountNumber.length)); - } - return ""; - } } diff --git a/server/src/main/java/server/haengdong/domain/event/EventRepository.java b/server/src/main/java/haengdong/event/domain/event/EventRepository.java similarity index 61% rename from server/src/main/java/server/haengdong/domain/event/EventRepository.java rename to server/src/main/java/haengdong/event/domain/event/EventRepository.java index 09526125e..df5a8b19d 100644 --- a/server/src/main/java/server/haengdong/domain/event/EventRepository.java +++ b/server/src/main/java/haengdong/event/domain/event/EventRepository.java @@ -1,5 +1,6 @@ -package server.haengdong.domain.event; +package haengdong.event.domain.event; +import java.util.List; import java.util.Optional; import org.springframework.data.jpa.repository.JpaRepository; import org.springframework.stereotype.Repository; @@ -8,4 +9,8 @@ public interface EventRepository extends JpaRepository { Optional findByToken(String token); + + boolean existsByTokenAndUserId(String token, Long userId); + + List findByUserId(Long userId); } diff --git a/server/src/main/java/server/haengdong/domain/event/Password.java b/server/src/main/java/haengdong/event/domain/event/Password.java similarity index 91% rename from server/src/main/java/server/haengdong/domain/event/Password.java rename to server/src/main/java/haengdong/event/domain/event/Password.java index 7c195b5d5..a18405267 100644 --- a/server/src/main/java/server/haengdong/domain/event/Password.java +++ b/server/src/main/java/haengdong/event/domain/event/Password.java @@ -1,4 +1,4 @@ -package server.haengdong.domain.event; +package haengdong.event.domain.event; import jakarta.persistence.Embeddable; import java.security.MessageDigest; @@ -9,8 +9,8 @@ import lombok.AccessLevel; import lombok.Getter; import lombok.NoArgsConstructor; -import server.haengdong.exception.HaengdongErrorCode; -import server.haengdong.exception.HaengdongException; +import haengdong.common.exception.HaengdongErrorCode; +import haengdong.common.exception.HaengdongException; @NoArgsConstructor(access = AccessLevel.PROTECTED) @Getter diff --git a/server/src/main/java/server/haengdong/domain/event/EventImage.java b/server/src/main/java/haengdong/event/domain/event/image/EventImage.java similarity index 87% rename from server/src/main/java/server/haengdong/domain/event/EventImage.java rename to server/src/main/java/haengdong/event/domain/event/image/EventImage.java index 16b2f5964..8d1c615a5 100644 --- a/server/src/main/java/server/haengdong/domain/event/EventImage.java +++ b/server/src/main/java/haengdong/event/domain/event/image/EventImage.java @@ -1,5 +1,6 @@ -package server.haengdong.domain.event; +package haengdong.event.domain.event.image; +import haengdong.event.domain.event.Event; import jakarta.persistence.Column; import jakarta.persistence.Entity; import jakarta.persistence.FetchType; @@ -11,7 +12,7 @@ import lombok.AccessLevel; import lombok.Getter; import lombok.NoArgsConstructor; -import server.haengdong.domain.BaseEntity; +import haengdong.common.domain.BaseEntity; @Getter @NoArgsConstructor(access = AccessLevel.PROTECTED) diff --git a/server/src/main/java/server/haengdong/domain/event/EventImageRepository.java b/server/src/main/java/haengdong/event/domain/event/image/EventImageRepository.java similarity index 82% rename from server/src/main/java/server/haengdong/domain/event/EventImageRepository.java rename to server/src/main/java/haengdong/event/domain/event/image/EventImageRepository.java index 0e00697f1..227c3de63 100644 --- a/server/src/main/java/server/haengdong/domain/event/EventImageRepository.java +++ b/server/src/main/java/haengdong/event/domain/event/image/EventImageRepository.java @@ -1,5 +1,6 @@ -package server.haengdong.domain.event; +package haengdong.event.domain.event.image; +import haengdong.event.domain.event.Event; import java.time.Instant; import java.util.List; import org.springframework.data.jpa.repository.JpaRepository; diff --git a/server/src/main/java/server/haengdong/domain/member/Member.java b/server/src/main/java/haengdong/event/domain/event/member/EventMember.java similarity index 76% rename from server/src/main/java/server/haengdong/domain/member/Member.java rename to server/src/main/java/haengdong/event/domain/event/member/EventMember.java index 2c9cb41d6..379ee4883 100644 --- a/server/src/main/java/server/haengdong/domain/member/Member.java +++ b/server/src/main/java/haengdong/event/domain/event/member/EventMember.java @@ -1,4 +1,4 @@ -package server.haengdong.domain.member; +package haengdong.event.domain.event.member; import jakarta.persistence.Column; import jakarta.persistence.Entity; @@ -14,16 +14,16 @@ import lombok.AccessLevel; import lombok.Getter; import lombok.NoArgsConstructor; -import server.haengdong.domain.BaseEntity; -import server.haengdong.domain.event.Event; -import server.haengdong.exception.HaengdongErrorCode; -import server.haengdong.exception.HaengdongException; +import haengdong.common.domain.BaseEntity; +import haengdong.event.domain.event.Event; +import haengdong.common.exception.HaengdongErrorCode; +import haengdong.common.exception.HaengdongException; @Getter @NoArgsConstructor(access = AccessLevel.PROTECTED) @Table(uniqueConstraints = {@UniqueConstraint(columnNames = {"event_id", "name"})}) @Entity -public class Member extends BaseEntity { +public class EventMember extends BaseEntity { private static final int MIN_NAME_LENGTH = 1; private static final int MAX_NAME_LENGTH = 8; @@ -42,11 +42,11 @@ public class Member extends BaseEntity { @Column(nullable = false) private boolean isDeposited; - public Member(Event event, String name) { + public EventMember(Event event, String name) { this(null, event, name, false); } - public Member(Long id, Event event, String name, boolean isDeposited) { + public EventMember(Long id, Event event, String name, boolean isDeposited) { validateName(name); this.id = id; this.event = event; @@ -66,6 +66,10 @@ public boolean hasName(String name) { return this.name.equals(name); } + public boolean isSameName(EventMember other) { + return this.name.equals(other.name); + } + @Override public boolean equals(Object o) { if (this == o) { @@ -74,8 +78,8 @@ public boolean equals(Object o) { if (o == null || getClass() != o.getClass()) { return false; } - Member member = (Member) o; - return Objects.equals(id, member.id); + EventMember eventMember = (EventMember) o; + return Objects.equals(id, eventMember.id); } @Override diff --git a/server/src/main/java/haengdong/event/domain/event/member/EventMemberRepository.java b/server/src/main/java/haengdong/event/domain/event/member/EventMemberRepository.java new file mode 100644 index 000000000..917708b1b --- /dev/null +++ b/server/src/main/java/haengdong/event/domain/event/member/EventMemberRepository.java @@ -0,0 +1,12 @@ +package haengdong.event.domain.event.member; + +import java.util.List; +import org.springframework.data.jpa.repository.JpaRepository; +import haengdong.event.domain.event.Event; + +public interface EventMemberRepository extends JpaRepository { + + List findAllByEvent(Event event); + + boolean existsByEventAndIsDeposited(Event event, boolean isDeposited); +} diff --git a/server/src/main/java/haengdong/event/domain/event/member/EventUniqueMembers.java b/server/src/main/java/haengdong/event/domain/event/member/EventUniqueMembers.java new file mode 100644 index 000000000..934e7c792 --- /dev/null +++ b/server/src/main/java/haengdong/event/domain/event/member/EventUniqueMembers.java @@ -0,0 +1,40 @@ +package haengdong.event.domain.event.member; + +import haengdong.common.exception.HaengdongErrorCode; +import haengdong.common.exception.HaengdongException; +import java.util.List; +import java.util.Set; +import java.util.stream.Collectors; +import lombok.Getter; + +@Getter +public class EventUniqueMembers { + + private final List eventMembers; + + public EventUniqueMembers(List eventMembers) { + validateDuplicateName(eventMembers); + this.eventMembers = eventMembers; + } + + private void validateDuplicateName(List eventMembers) { + Set uniqueNames = eventMembers.stream() + .map(EventMember::getName) + .distinct() + .collect(Collectors.toSet()); + + if (eventMembers.size() != uniqueNames.size()) { + throw new HaengdongException(HaengdongErrorCode.MEMBER_NAME_DUPLICATE); + } + } + + public boolean containName(List others) { + return others.stream() + .anyMatch(this::containName); + } + + private boolean containName(EventMember other) { + return eventMembers.stream() + .anyMatch(member -> member.isSameName(other)); + } +} diff --git a/server/src/main/java/haengdong/event/domain/event/member/UpdatedMembers.java b/server/src/main/java/haengdong/event/domain/event/member/UpdatedMembers.java new file mode 100644 index 000000000..31a989d5e --- /dev/null +++ b/server/src/main/java/haengdong/event/domain/event/member/UpdatedMembers.java @@ -0,0 +1,67 @@ +package haengdong.event.domain.event.member; + +import java.util.HashSet; +import java.util.List; +import java.util.Set; +import java.util.stream.Collectors; +import haengdong.common.exception.HaengdongErrorCode; +import haengdong.common.exception.HaengdongException; + +public class UpdatedMembers { + + private final Set eventMembers; + + public UpdatedMembers(List eventMembers) { + validateMemberUnique(eventMembers); + validateNameUnique(eventMembers); + this.eventMembers = new HashSet<>(eventMembers); + } + + private void validateMemberUnique(List eventMembers) { + if (eventMembers.size() != Set.copyOf(eventMembers).size()) { + throw new HaengdongException(HaengdongErrorCode.MEMBER_NAME_CHANGE_DUPLICATE); + } + } + + private void validateNameUnique(List eventMembers) { + Set uniqueNames = eventMembers.stream() + .map(EventMember::getName) + .collect(Collectors.toSet()); + if (eventMembers.size() != uniqueNames.size()) { + throw new HaengdongException(HaengdongErrorCode.MEMBER_NAME_CHANGE_DUPLICATE); + } + } + + public void validateUpdatable(List originEventMembers) { + Set uniqueEventMembers = Set.copyOf(originEventMembers); + validateUpdatedMembersExist(uniqueEventMembers); + validateUpdatedNamesUnique(uniqueEventMembers); + } + + private void validateUpdatedMembersExist(Set originEventMembers) { + if (!this.eventMembers.equals(originEventMembers)) { + throw new HaengdongException(HaengdongErrorCode.MEMBER_UPDATE_MISMATCH); + } + } + + private void validateUpdatedNamesUnique(Set originEventMembers) { + boolean duplicated = originEventMembers.stream() + .anyMatch(this::isMemberNameUpdated); + + if (duplicated) { + throw new HaengdongException(HaengdongErrorCode.MEMBER_NAME_DUPLICATE); + } + } + + private boolean isMemberNameUpdated(EventMember originMembers) { + return this.eventMembers.stream() + .filter(member -> !member.getId().equals(originMembers.getId())) + .anyMatch(member -> member.hasName(originMembers.getName())); + } + + public List getMembers() { + return eventMembers.stream().toList(); + } +} + + diff --git a/server/src/main/java/haengdong/event/domain/step/Step.java b/server/src/main/java/haengdong/event/domain/step/Step.java new file mode 100644 index 000000000..06ce56577 --- /dev/null +++ b/server/src/main/java/haengdong/event/domain/step/Step.java @@ -0,0 +1,50 @@ +package haengdong.event.domain.step; + +import java.util.ArrayList; +import java.util.HashSet; +import java.util.List; +import java.util.Set; +import haengdong.event.domain.bill.Bill; +import haengdong.event.domain.event.member.EventMember; +import haengdong.common.exception.HaengdongErrorCode; +import haengdong.common.exception.HaengdongException; + +public class Step { + + private final List bills; + private final Set eventMembers; + + private Step(List bills, Set eventMembers) { + this.bills = bills; + this.eventMembers = eventMembers; + } + + public static Step of(Bill bill) { + List bills = new ArrayList<>(); + bills.add(bill); + Set eventMembers = new HashSet<>(bill.getMembers()); + + return new Step(bills, eventMembers); + } + + public void add(Bill bill) { + if (isNotSameMember(bill)) { + throw new HaengdongException(HaengdongErrorCode.DIFFERENT_STEP_MEMBERS); + } + + bills.add(bill); + } + + public boolean isNotSameMember(Bill bill) { + Set otherEventMembers = Set.copyOf(bill.getMembers()); + return !eventMembers.equals(otherEventMembers); + } + + public List getBills() { + return bills; + } + + public Set getMembers() { + return eventMembers; + } +} diff --git a/server/src/main/java/server/haengdong/domain/step/Steps.java b/server/src/main/java/haengdong/event/domain/step/Steps.java similarity index 89% rename from server/src/main/java/server/haengdong/domain/step/Steps.java rename to server/src/main/java/haengdong/event/domain/step/Steps.java index f1ad8c746..c15bc9414 100644 --- a/server/src/main/java/server/haengdong/domain/step/Steps.java +++ b/server/src/main/java/haengdong/event/domain/step/Steps.java @@ -1,8 +1,8 @@ -package server.haengdong.domain.step; +package haengdong.event.domain.step; import java.util.ArrayList; import java.util.List; -import server.haengdong.domain.bill.Bill; +import haengdong.event.domain.bill.Bill; public class Steps { diff --git a/server/src/main/java/server/haengdong/infrastructure/UUIDProvider.java b/server/src/main/java/haengdong/event/infrastructure/UUIDProvider.java similarity index 71% rename from server/src/main/java/server/haengdong/infrastructure/UUIDProvider.java rename to server/src/main/java/haengdong/event/infrastructure/UUIDProvider.java index 39a97cadb..e2e34f46b 100644 --- a/server/src/main/java/server/haengdong/infrastructure/UUIDProvider.java +++ b/server/src/main/java/haengdong/event/infrastructure/UUIDProvider.java @@ -1,8 +1,8 @@ -package server.haengdong.infrastructure; +package haengdong.event.infrastructure; import java.util.UUID; import org.springframework.stereotype.Component; -import server.haengdong.domain.RandomValueProvider; +import haengdong.event.domain.RandomValueProvider; @Component public class UUIDProvider implements RandomValueProvider { diff --git a/server/src/main/java/server/haengdong/presentation/BillController.java b/server/src/main/java/haengdong/event/presentation/BillController.java similarity index 79% rename from server/src/main/java/server/haengdong/presentation/BillController.java rename to server/src/main/java/haengdong/event/presentation/BillController.java index f1a4f74f4..5ea9bd9ac 100644 --- a/server/src/main/java/server/haengdong/presentation/BillController.java +++ b/server/src/main/java/haengdong/event/presentation/BillController.java @@ -1,14 +1,14 @@ -package server.haengdong.presentation; +package haengdong.event.presentation; import lombok.RequiredArgsConstructor; import org.springframework.http.ResponseEntity; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.PathVariable; import org.springframework.web.bind.annotation.RestController; -import server.haengdong.application.BillService; -import server.haengdong.application.response.BillDetailsAppResponse; -import server.haengdong.presentation.response.BillDetailsResponse; -import server.haengdong.presentation.response.StepsResponse; +import haengdong.event.application.BillService; +import haengdong.event.application.response.BillDetailsAppResponse; +import haengdong.event.presentation.response.BillDetailsResponse; +import haengdong.event.presentation.response.StepsResponse; @RequiredArgsConstructor @RestController diff --git a/server/src/main/java/server/haengdong/presentation/EventController.java b/server/src/main/java/haengdong/event/presentation/EventController.java similarity index 56% rename from server/src/main/java/server/haengdong/presentation/EventController.java rename to server/src/main/java/haengdong/event/presentation/EventController.java index 47bdd4fce..e64e131cd 100644 --- a/server/src/main/java/server/haengdong/presentation/EventController.java +++ b/server/src/main/java/haengdong/event/presentation/EventController.java @@ -1,5 +1,23 @@ -package server.haengdong.presentation; +package haengdong.event.presentation; +import haengdong.common.auth.Login; +import haengdong.common.auth.application.AuthService; +import haengdong.common.properties.CookieProperties; +import haengdong.event.application.EventImageFacadeService; +import haengdong.event.application.EventService; +import haengdong.event.application.request.EventAppRequest; +import haengdong.event.application.request.EventMineAppResponse; +import haengdong.event.application.response.EventAppResponse; +import haengdong.event.application.response.EventImageUrlAppResponse; +import haengdong.event.application.response.MemberBillReportAppResponse; +import haengdong.event.presentation.request.EventGuestSaveRequest; +import haengdong.event.presentation.request.EventLoginRequest; +import haengdong.event.presentation.request.EventSaveRequest; +import haengdong.event.presentation.response.EventDetailResponse; +import haengdong.event.presentation.response.EventImagesResponse; +import haengdong.event.presentation.response.EventResponse; +import haengdong.event.presentation.response.EventsMineResponse; +import haengdong.event.presentation.response.MemberBillReportsResponse; import jakarta.validation.Valid; import java.util.List; import lombok.RequiredArgsConstructor; @@ -13,17 +31,6 @@ import org.springframework.web.bind.annotation.PostMapping; import org.springframework.web.bind.annotation.RequestBody; import org.springframework.web.bind.annotation.RestController; -import server.haengdong.application.AuthService; -import server.haengdong.application.response.EventImageAppResponse; -import server.haengdong.application.EventService; -import server.haengdong.application.response.MemberBillReportAppResponse; -import server.haengdong.infrastructure.auth.CookieProperties; -import server.haengdong.presentation.request.EventLoginRequest; -import server.haengdong.presentation.request.EventSaveRequest; -import server.haengdong.presentation.response.EventDetailResponse; -import server.haengdong.presentation.response.EventImagesResponse; -import server.haengdong.presentation.response.EventResponse; -import server.haengdong.presentation.response.MemberBillReportsResponse; @Slf4j @RequiredArgsConstructor @@ -34,6 +41,7 @@ public class EventController { private final EventService eventService; private final AuthService authService; private final CookieProperties cookieProperties; + private final EventImageFacadeService eventImageFacadeService; @GetMapping("/api/events/{eventId}") public ResponseEntity findEvent(@PathVariable("eventId") String token) { @@ -42,6 +50,13 @@ public ResponseEntity findEvent(@PathVariable("eventId") St return ResponseEntity.ok(eventDetailResponse); } + @GetMapping("/api/events/mine") + public ResponseEntity findMyEvents(@Login Long userId) { + List responses = eventService.findByUserId(userId); + + return ResponseEntity.ok(EventsMineResponse.of(responses)); + } + @GetMapping("/api/events/{eventId}/reports") public ResponseEntity getMemberBillReports(@PathVariable("eventId") String token) { List memberBillReports = eventService.getMemberBillReports(token); @@ -50,11 +65,12 @@ public ResponseEntity getMemberBillReports(@PathVaria .body(MemberBillReportsResponse.of(memberBillReports)); } - @PostMapping("/api/events") - public ResponseEntity saveEvent(@Valid @RequestBody EventSaveRequest request) { - EventResponse eventResponse = EventResponse.of(eventService.saveEvent(request.toAppRequest())); + @PostMapping("/api/events/guest") + public ResponseEntity saveEventGuest(@Valid @RequestBody EventGuestSaveRequest request) { + EventAppResponse eventAppResponse = eventService.saveEventGuest(request.toAppRequest()); + EventResponse eventResponse = EventResponse.of(eventAppResponse); - String jwtToken = authService.createToken(eventResponse.eventId()); + String jwtToken = authService.createGuestToken(eventAppResponse.userId()); ResponseCookie responseCookie = createResponseCookie(jwtToken); return ResponseEntity.ok() @@ -62,13 +78,19 @@ public ResponseEntity saveEvent(@Valid @RequestBody EventSaveRequ .body(eventResponse); } + @PostMapping("/api/events") + public ResponseEntity saveEvent(@Login Long userId, @Valid @RequestBody EventSaveRequest request) { + EventResponse eventResponse = EventResponse.of(eventService.saveEvent(new EventAppRequest(request.eventName(), userId))); + return ResponseEntity.ok(eventResponse); + } + @PostMapping("/api/events/{eventId}/login") public ResponseEntity loginEvent( @PathVariable("eventId") String token, @Valid @RequestBody EventLoginRequest request ) { - eventService.validatePassword(request.toAppRequest(token)); - String jwtToken = authService.createToken(token); + EventAppResponse response = eventService.findByGuestPassword(request.toAppRequest(token)); + String jwtToken = authService.createGuestToken(response.userId()); ResponseCookie responseCookie = createResponseCookie(jwtToken); return ResponseEntity.ok() @@ -89,7 +111,7 @@ private ResponseCookie createResponseCookie(String token) { @GetMapping("/api/events/{eventId}/images") public ResponseEntity findAllImages(@PathVariable("eventId") String token) { - List images = eventService.findImages(token); + List images = eventImageFacadeService.findImages(token); return ResponseEntity.ok(EventImagesResponse.of(images)); } diff --git a/server/src/main/java/server/haengdong/presentation/MemberController.java b/server/src/main/java/haengdong/event/presentation/EventMemberController.java similarity index 59% rename from server/src/main/java/server/haengdong/presentation/MemberController.java rename to server/src/main/java/haengdong/event/presentation/EventMemberController.java index f5662f9b2..09d5558bd 100644 --- a/server/src/main/java/server/haengdong/presentation/MemberController.java +++ b/server/src/main/java/haengdong/event/presentation/EventMemberController.java @@ -1,4 +1,4 @@ -package server.haengdong.presentation; +package haengdong.event.presentation; import java.util.List; import lombok.RequiredArgsConstructor; @@ -7,28 +7,28 @@ import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.PathVariable; import org.springframework.web.bind.annotation.RestController; -import server.haengdong.application.MemberService; -import server.haengdong.application.response.MemberAppResponse; -import server.haengdong.presentation.response.CurrentMembersResponse; -import server.haengdong.presentation.response.MembersResponse; +import haengdong.event.application.EventMemberService; +import haengdong.event.application.response.MemberAppResponse; +import haengdong.event.presentation.response.CurrentMembersResponse; +import haengdong.event.presentation.response.MembersResponse; @Slf4j @RequiredArgsConstructor @RestController -public class MemberController { +public class EventMemberController { - private final MemberService memberService; + private final EventMemberService eventMemberService; @GetMapping("/api/events/{eventId}/members") public ResponseEntity findAllMembers(@PathVariable("eventId") String token) { - MembersResponse response = MembersResponse.of(memberService.findAllMembers(token)); + MembersResponse response = MembersResponse.of(eventMemberService.findAllMembers(token)); return ResponseEntity.ok(response); } @GetMapping("/api/events/{eventId}/members/current") public ResponseEntity getCurrentMembers(@PathVariable("eventId") String token) { - List currentMembers = memberService.getCurrentMembers(token); + List currentMembers = eventMemberService.getCurrentMembers(token); return ResponseEntity.ok() .body(CurrentMembersResponse.of(currentMembers)); diff --git a/server/src/main/java/server/haengdong/presentation/admin/AdminBillController.java b/server/src/main/java/haengdong/event/presentation/admin/AdminBillController.java similarity index 87% rename from server/src/main/java/server/haengdong/presentation/admin/AdminBillController.java rename to server/src/main/java/haengdong/event/presentation/admin/AdminBillController.java index 5e65c04f9..bea39a868 100644 --- a/server/src/main/java/server/haengdong/presentation/admin/AdminBillController.java +++ b/server/src/main/java/haengdong/event/presentation/admin/AdminBillController.java @@ -1,4 +1,4 @@ -package server.haengdong.presentation.admin; +package haengdong.event.presentation.admin; import jakarta.validation.Valid; import lombok.RequiredArgsConstructor; @@ -9,10 +9,10 @@ import org.springframework.web.bind.annotation.PutMapping; import org.springframework.web.bind.annotation.RequestBody; import org.springframework.web.bind.annotation.RestController; -import server.haengdong.application.BillService; -import server.haengdong.presentation.request.BillDetailsUpdateRequest; -import server.haengdong.presentation.request.BillSaveRequest; -import server.haengdong.presentation.request.BillUpdateRequest; +import haengdong.event.application.BillService; +import haengdong.event.presentation.request.BillDetailsUpdateRequest; +import haengdong.event.presentation.request.BillSaveRequest; +import haengdong.event.presentation.request.BillUpdateRequest; @RequiredArgsConstructor @RestController diff --git a/server/src/main/java/server/haengdong/presentation/admin/AdminEventController.java b/server/src/main/java/haengdong/event/presentation/admin/AdminEventController.java similarity index 87% rename from server/src/main/java/server/haengdong/presentation/admin/AdminEventController.java rename to server/src/main/java/haengdong/event/presentation/admin/AdminEventController.java index 81434aeba..bcd9a056f 100644 --- a/server/src/main/java/server/haengdong/presentation/admin/AdminEventController.java +++ b/server/src/main/java/haengdong/event/presentation/admin/AdminEventController.java @@ -1,5 +1,8 @@ -package server.haengdong.presentation.admin; +package haengdong.event.presentation.admin; +import haengdong.event.application.EventImageFacadeService; +import haengdong.event.application.EventService; +import haengdong.event.presentation.request.EventUpdateRequest; import jakarta.validation.Valid; import java.util.List; import lombok.RequiredArgsConstructor; @@ -13,9 +16,6 @@ import org.springframework.web.bind.annotation.RequestPart; import org.springframework.web.bind.annotation.RestController; import org.springframework.web.multipart.MultipartFile; -import server.haengdong.application.EventImageFacadeService; -import server.haengdong.application.EventService; -import server.haengdong.presentation.request.EventUpdateRequest; @Slf4j @RequiredArgsConstructor @@ -35,8 +35,7 @@ public ResponseEntity updateEvent( @PathVariable("eventId") String token, @Valid @RequestBody EventUpdateRequest request ) { - eventService.updateEvent(token, request.toAppRequest()); - + eventService.updateEventName(token, request.toAppRequest()); return ResponseEntity.ok().build(); } diff --git a/server/src/main/java/server/haengdong/presentation/admin/AdminMemberController.java b/server/src/main/java/haengdong/event/presentation/admin/AdminMemberController.java similarity index 69% rename from server/src/main/java/server/haengdong/presentation/admin/AdminMemberController.java rename to server/src/main/java/haengdong/event/presentation/admin/AdminMemberController.java index 22cb0190a..37350c39d 100644 --- a/server/src/main/java/server/haengdong/presentation/admin/AdminMemberController.java +++ b/server/src/main/java/haengdong/event/presentation/admin/AdminMemberController.java @@ -1,4 +1,4 @@ -package server.haengdong.presentation.admin; +package haengdong.event.presentation.admin; import jakarta.validation.Valid; import lombok.RequiredArgsConstructor; @@ -10,25 +10,25 @@ import org.springframework.web.bind.annotation.PutMapping; import org.springframework.web.bind.annotation.RequestBody; import org.springframework.web.bind.annotation.RestController; -import server.haengdong.application.MemberService; -import server.haengdong.application.response.MembersSaveAppResponse; -import server.haengdong.presentation.request.MembersSaveRequest; -import server.haengdong.presentation.request.MembersUpdateRequest; -import server.haengdong.presentation.response.MembersSaveResponse; +import haengdong.event.application.EventMemberService; +import haengdong.event.application.response.MembersSaveAppResponse; +import haengdong.event.presentation.request.MembersSaveRequest; +import haengdong.event.presentation.request.MembersUpdateRequest; +import haengdong.event.presentation.response.MembersSaveResponse; @Slf4j @RequiredArgsConstructor @RestController public class AdminMemberController { - private final MemberService memberService; + private final EventMemberService eventMemberService; @PostMapping("/api/admin/events/{eventId}/members") public ResponseEntity saveMembers( @PathVariable("eventId") String token, @Valid @RequestBody MembersSaveRequest request ) { - MembersSaveAppResponse response = memberService.saveMembers(token, request.toAppRequest()); + MembersSaveAppResponse response = eventMemberService.saveMembers(token, request.toAppRequest()); return ResponseEntity.ok(MembersSaveResponse.of(response)); } @@ -38,7 +38,7 @@ public ResponseEntity updateMembers( @PathVariable("eventId") String token, @Valid @RequestBody MembersUpdateRequest request ) { - memberService.updateMembers(token, request.toAppRequest()); + eventMemberService.updateMembers(token, request.toAppRequest()); return ResponseEntity.ok().build(); } @@ -48,7 +48,7 @@ public ResponseEntity deleteMember( @PathVariable("eventId") String token, @PathVariable("memberId") Long memberId ) { - memberService.deleteMember(token, memberId); + eventMemberService.deleteMember(token, memberId); return ResponseEntity.ok().build(); } diff --git a/server/src/main/java/server/haengdong/presentation/request/BillDetailUpdateRequest.java b/server/src/main/java/haengdong/event/presentation/request/BillDetailUpdateRequest.java similarity index 79% rename from server/src/main/java/server/haengdong/presentation/request/BillDetailUpdateRequest.java rename to server/src/main/java/haengdong/event/presentation/request/BillDetailUpdateRequest.java index d0f69b148..5a4dfcf5f 100644 --- a/server/src/main/java/server/haengdong/presentation/request/BillDetailUpdateRequest.java +++ b/server/src/main/java/haengdong/event/presentation/request/BillDetailUpdateRequest.java @@ -1,7 +1,7 @@ -package server.haengdong.presentation.request; +package haengdong.event.presentation.request; import jakarta.validation.constraints.NotNull; -import server.haengdong.application.request.BillDetailUpdateAppRequest; +import haengdong.event.application.request.BillDetailUpdateAppRequest; public record BillDetailUpdateRequest( diff --git a/server/src/main/java/server/haengdong/presentation/request/BillDetailsUpdateRequest.java b/server/src/main/java/haengdong/event/presentation/request/BillDetailsUpdateRequest.java similarity index 79% rename from server/src/main/java/server/haengdong/presentation/request/BillDetailsUpdateRequest.java rename to server/src/main/java/haengdong/event/presentation/request/BillDetailsUpdateRequest.java index 091db5967..ac70f3573 100644 --- a/server/src/main/java/server/haengdong/presentation/request/BillDetailsUpdateRequest.java +++ b/server/src/main/java/haengdong/event/presentation/request/BillDetailsUpdateRequest.java @@ -1,9 +1,9 @@ -package server.haengdong.presentation.request; +package haengdong.event.presentation.request; import jakarta.validation.Valid; import jakarta.validation.constraints.NotEmpty; import java.util.List; -import server.haengdong.application.request.BillDetailsUpdateAppRequest; +import haengdong.event.application.request.BillDetailsUpdateAppRequest; public record BillDetailsUpdateRequest( diff --git a/server/src/main/java/server/haengdong/presentation/request/BillSaveRequest.java b/server/src/main/java/haengdong/event/presentation/request/BillSaveRequest.java similarity index 84% rename from server/src/main/java/server/haengdong/presentation/request/BillSaveRequest.java rename to server/src/main/java/haengdong/event/presentation/request/BillSaveRequest.java index 1a7365a6e..1fe4367a6 100644 --- a/server/src/main/java/server/haengdong/presentation/request/BillSaveRequest.java +++ b/server/src/main/java/haengdong/event/presentation/request/BillSaveRequest.java @@ -1,10 +1,10 @@ -package server.haengdong.presentation.request; +package haengdong.event.presentation.request; import jakarta.validation.constraints.NotBlank; import jakarta.validation.constraints.NotEmpty; import jakarta.validation.constraints.NotNull; import java.util.List; -import server.haengdong.application.request.BillAppRequest; +import haengdong.event.application.request.BillAppRequest; public record BillSaveRequest( diff --git a/server/src/main/java/server/haengdong/presentation/request/BillUpdateRequest.java b/server/src/main/java/haengdong/event/presentation/request/BillUpdateRequest.java similarity index 79% rename from server/src/main/java/server/haengdong/presentation/request/BillUpdateRequest.java rename to server/src/main/java/haengdong/event/presentation/request/BillUpdateRequest.java index d5ea67474..eb65578f1 100644 --- a/server/src/main/java/server/haengdong/presentation/request/BillUpdateRequest.java +++ b/server/src/main/java/haengdong/event/presentation/request/BillUpdateRequest.java @@ -1,8 +1,8 @@ -package server.haengdong.presentation.request; +package haengdong.event.presentation.request; import jakarta.validation.constraints.NotBlank; import jakarta.validation.constraints.NotNull; -import server.haengdong.application.request.BillUpdateAppRequest; +import haengdong.event.application.request.BillUpdateAppRequest; public record BillUpdateRequest( diff --git a/server/src/main/java/haengdong/event/presentation/request/EventGuestSaveRequest.java b/server/src/main/java/haengdong/event/presentation/request/EventGuestSaveRequest.java new file mode 100644 index 000000000..27a613308 --- /dev/null +++ b/server/src/main/java/haengdong/event/presentation/request/EventGuestSaveRequest.java @@ -0,0 +1,21 @@ +package haengdong.event.presentation.request; + +import jakarta.validation.constraints.NotBlank; +import haengdong.event.application.request.EventGuestAppRequest; + +public record EventGuestSaveRequest( + + @NotBlank(message = "행사 이름은 공백일 수 없습니다.") + String eventName, + + @NotBlank(message = "행사 이름은 공백일 수 없습니다.") + String nickname, + + @NotBlank(message = "비밀번호는 공백일 수 없습니다.") + String password +) { + + public EventGuestAppRequest toAppRequest() { + return new EventGuestAppRequest(eventName, nickname, password); + } +} diff --git a/server/src/main/java/server/haengdong/presentation/request/EventLoginRequest.java b/server/src/main/java/haengdong/event/presentation/request/EventLoginRequest.java similarity index 73% rename from server/src/main/java/server/haengdong/presentation/request/EventLoginRequest.java rename to server/src/main/java/haengdong/event/presentation/request/EventLoginRequest.java index d49a0e510..43a0dfa6d 100644 --- a/server/src/main/java/server/haengdong/presentation/request/EventLoginRequest.java +++ b/server/src/main/java/haengdong/event/presentation/request/EventLoginRequest.java @@ -1,7 +1,7 @@ -package server.haengdong.presentation.request; +package haengdong.event.presentation.request; import jakarta.validation.constraints.NotBlank; -import server.haengdong.application.request.EventLoginAppRequest; +import haengdong.event.application.request.EventLoginAppRequest; public record EventLoginRequest( diff --git a/server/src/main/java/haengdong/event/presentation/request/EventSaveRequest.java b/server/src/main/java/haengdong/event/presentation/request/EventSaveRequest.java new file mode 100644 index 000000000..8447b3d6f --- /dev/null +++ b/server/src/main/java/haengdong/event/presentation/request/EventSaveRequest.java @@ -0,0 +1,9 @@ +package haengdong.event.presentation.request; + +import jakarta.validation.constraints.NotBlank; + +public record EventSaveRequest( + @NotBlank(message = "행사 이름은 공백일 수 없습니다.") + String eventName +) { +} diff --git a/server/src/main/java/haengdong/event/presentation/request/EventUpdateRequest.java b/server/src/main/java/haengdong/event/presentation/request/EventUpdateRequest.java new file mode 100644 index 000000000..37db577f9 --- /dev/null +++ b/server/src/main/java/haengdong/event/presentation/request/EventUpdateRequest.java @@ -0,0 +1,14 @@ +package haengdong.event.presentation.request; + +import haengdong.event.application.request.EventUpdateAppRequest; +import jakarta.validation.constraints.NotBlank; + +public record EventUpdateRequest( + @NotBlank + String eventName +) { + + public EventUpdateAppRequest toAppRequest() { + return new EventUpdateAppRequest(eventName); + } +} diff --git a/server/src/main/java/server/haengdong/presentation/request/MemberSaveRequest.java b/server/src/main/java/haengdong/event/presentation/request/MemberSaveRequest.java similarity index 80% rename from server/src/main/java/server/haengdong/presentation/request/MemberSaveRequest.java rename to server/src/main/java/haengdong/event/presentation/request/MemberSaveRequest.java index 8b763be09..e400c48a0 100644 --- a/server/src/main/java/server/haengdong/presentation/request/MemberSaveRequest.java +++ b/server/src/main/java/haengdong/event/presentation/request/MemberSaveRequest.java @@ -1,4 +1,4 @@ -package server.haengdong.presentation.request; +package haengdong.event.presentation.request; import jakarta.validation.constraints.NotBlank; diff --git a/server/src/main/java/server/haengdong/presentation/request/MemberUpdateRequest.java b/server/src/main/java/haengdong/event/presentation/request/MemberUpdateRequest.java similarity index 82% rename from server/src/main/java/server/haengdong/presentation/request/MemberUpdateRequest.java rename to server/src/main/java/haengdong/event/presentation/request/MemberUpdateRequest.java index 1f3bfe95a..971488d6f 100644 --- a/server/src/main/java/server/haengdong/presentation/request/MemberUpdateRequest.java +++ b/server/src/main/java/haengdong/event/presentation/request/MemberUpdateRequest.java @@ -1,8 +1,8 @@ -package server.haengdong.presentation.request; +package haengdong.event.presentation.request; import jakarta.validation.constraints.NotBlank; import jakarta.validation.constraints.NotNull; -import server.haengdong.application.request.MemberUpdateAppRequest; +import haengdong.event.application.request.MemberUpdateAppRequest; public record MemberUpdateRequest( diff --git a/server/src/main/java/server/haengdong/presentation/request/MembersSaveRequest.java b/server/src/main/java/haengdong/event/presentation/request/MembersSaveRequest.java similarity index 64% rename from server/src/main/java/server/haengdong/presentation/request/MembersSaveRequest.java rename to server/src/main/java/haengdong/event/presentation/request/MembersSaveRequest.java index cc611742a..cea642ab7 100644 --- a/server/src/main/java/server/haengdong/presentation/request/MembersSaveRequest.java +++ b/server/src/main/java/haengdong/event/presentation/request/MembersSaveRequest.java @@ -1,8 +1,8 @@ -package server.haengdong.presentation.request; +package haengdong.event.presentation.request; import java.util.List; -import server.haengdong.application.request.MemberSaveAppRequest; -import server.haengdong.application.request.MembersSaveAppRequest; +import haengdong.event.application.request.MemberSaveAppRequest; +import haengdong.event.application.request.MembersSaveAppRequest; public record MembersSaveRequest( List members diff --git a/server/src/main/java/server/haengdong/presentation/request/MembersUpdateRequest.java b/server/src/main/java/haengdong/event/presentation/request/MembersUpdateRequest.java similarity index 78% rename from server/src/main/java/server/haengdong/presentation/request/MembersUpdateRequest.java rename to server/src/main/java/haengdong/event/presentation/request/MembersUpdateRequest.java index db3715130..0b7608ddb 100644 --- a/server/src/main/java/server/haengdong/presentation/request/MembersUpdateRequest.java +++ b/server/src/main/java/haengdong/event/presentation/request/MembersUpdateRequest.java @@ -1,9 +1,9 @@ -package server.haengdong.presentation.request; +package haengdong.event.presentation.request; import jakarta.validation.Valid; import jakarta.validation.constraints.NotNull; import java.util.List; -import server.haengdong.application.request.MembersUpdateAppRequest; +import haengdong.event.application.request.MembersUpdateAppRequest; public record MembersUpdateRequest( diff --git a/server/src/main/java/server/haengdong/presentation/response/BillDetailResponse.java b/server/src/main/java/haengdong/event/presentation/response/BillDetailResponse.java similarity index 80% rename from server/src/main/java/server/haengdong/presentation/response/BillDetailResponse.java rename to server/src/main/java/haengdong/event/presentation/response/BillDetailResponse.java index 9ff993b8a..c20b02525 100644 --- a/server/src/main/java/server/haengdong/presentation/response/BillDetailResponse.java +++ b/server/src/main/java/haengdong/event/presentation/response/BillDetailResponse.java @@ -1,6 +1,6 @@ -package server.haengdong.presentation.response; +package haengdong.event.presentation.response; -import server.haengdong.application.response.BillDetailAppResponse; +import haengdong.event.application.response.BillDetailAppResponse; public record BillDetailResponse( Long id, diff --git a/server/src/main/java/server/haengdong/presentation/response/BillDetailsResponse.java b/server/src/main/java/haengdong/event/presentation/response/BillDetailsResponse.java similarity index 79% rename from server/src/main/java/server/haengdong/presentation/response/BillDetailsResponse.java rename to server/src/main/java/haengdong/event/presentation/response/BillDetailsResponse.java index 888b0160d..998eec2b3 100644 --- a/server/src/main/java/server/haengdong/presentation/response/BillDetailsResponse.java +++ b/server/src/main/java/haengdong/event/presentation/response/BillDetailsResponse.java @@ -1,8 +1,8 @@ -package server.haengdong.presentation.response; +package haengdong.event.presentation.response; import java.util.List; import java.util.stream.Collectors; -import server.haengdong.application.response.BillDetailsAppResponse; +import haengdong.event.application.response.BillDetailsAppResponse; public record BillDetailsResponse( List members diff --git a/server/src/main/java/server/haengdong/presentation/response/BillResponse.java b/server/src/main/java/haengdong/event/presentation/response/BillResponse.java similarity index 72% rename from server/src/main/java/server/haengdong/presentation/response/BillResponse.java rename to server/src/main/java/haengdong/event/presentation/response/BillResponse.java index 0f3aaeaa0..c85c7e4d2 100644 --- a/server/src/main/java/server/haengdong/presentation/response/BillResponse.java +++ b/server/src/main/java/haengdong/event/presentation/response/BillResponse.java @@ -1,6 +1,6 @@ -package server.haengdong.presentation.response; +package haengdong.event.presentation.response; -import server.haengdong.application.response.BillAppResponse; +import haengdong.event.application.response.BillAppResponse; public record BillResponse( Long id, diff --git a/server/src/main/java/server/haengdong/presentation/response/CurrentMembersResponse.java b/server/src/main/java/haengdong/event/presentation/response/CurrentMembersResponse.java similarity index 67% rename from server/src/main/java/server/haengdong/presentation/response/CurrentMembersResponse.java rename to server/src/main/java/haengdong/event/presentation/response/CurrentMembersResponse.java index b1fe5720b..1ed19888d 100644 --- a/server/src/main/java/server/haengdong/presentation/response/CurrentMembersResponse.java +++ b/server/src/main/java/haengdong/event/presentation/response/CurrentMembersResponse.java @@ -1,8 +1,7 @@ -package server.haengdong.presentation.response; +package haengdong.event.presentation.response; import java.util.List; -import server.haengdong.application.response.LastBillMemberAppResponse; -import server.haengdong.application.response.MemberAppResponse; +import haengdong.event.application.response.MemberAppResponse; public record CurrentMembersResponse(List members) { diff --git a/server/src/main/java/haengdong/event/presentation/response/EventDetailResponse.java b/server/src/main/java/haengdong/event/presentation/response/EventDetailResponse.java new file mode 100644 index 000000000..8f7a1a4a6 --- /dev/null +++ b/server/src/main/java/haengdong/event/presentation/response/EventDetailResponse.java @@ -0,0 +1,15 @@ +package haengdong.event.presentation.response; + +import haengdong.event.application.response.EventDetailAppResponse; + +public record EventDetailResponse( + String eventName, + String bankName, + String accountNumber, + Boolean createdByGuest +) { + + public static EventDetailResponse of(EventDetailAppResponse response) { + return new EventDetailResponse(response.eventName(), response.bankName(), response.accountNumber(), response.createdByGuest()); + } +} diff --git a/server/src/main/java/haengdong/event/presentation/response/EventImageResponse.java b/server/src/main/java/haengdong/event/presentation/response/EventImageResponse.java new file mode 100644 index 000000000..3a8b4c5e2 --- /dev/null +++ b/server/src/main/java/haengdong/event/presentation/response/EventImageResponse.java @@ -0,0 +1,13 @@ +package haengdong.event.presentation.response; + +import haengdong.event.application.response.EventImageUrlAppResponse; + +public record EventImageResponse( + Long id, + String url +) { + + public static EventImageResponse of(EventImageUrlAppResponse response) { + return new EventImageResponse(response.id(), response.url()); + } +} diff --git a/server/src/main/java/server/haengdong/presentation/response/EventImagesResponse.java b/server/src/main/java/haengdong/event/presentation/response/EventImagesResponse.java similarity index 58% rename from server/src/main/java/server/haengdong/presentation/response/EventImagesResponse.java rename to server/src/main/java/haengdong/event/presentation/response/EventImagesResponse.java index d5c2b0ab8..2addc2e55 100644 --- a/server/src/main/java/server/haengdong/presentation/response/EventImagesResponse.java +++ b/server/src/main/java/haengdong/event/presentation/response/EventImagesResponse.java @@ -1,11 +1,11 @@ -package server.haengdong.presentation.response; +package haengdong.event.presentation.response; +import haengdong.event.application.response.EventImageUrlAppResponse; import java.util.List; -import server.haengdong.application.response.EventImageAppResponse; public record EventImagesResponse(List images) { - public static EventImagesResponse of(List responses) { + public static EventImagesResponse of(List responses) { List images = responses.stream() .map(EventImageResponse::of) .toList(); diff --git a/server/src/main/java/haengdong/event/presentation/response/EventMineResponse.java b/server/src/main/java/haengdong/event/presentation/response/EventMineResponse.java new file mode 100644 index 000000000..c5af6cf29 --- /dev/null +++ b/server/src/main/java/haengdong/event/presentation/response/EventMineResponse.java @@ -0,0 +1,16 @@ +package haengdong.event.presentation.response; + +import haengdong.event.application.request.EventMineAppResponse; +import java.time.LocalDateTime; + +public record EventMineResponse( + String eventId, + String eventName, + boolean isFinished, + LocalDateTime createdAt +) { + + public static EventMineResponse of(EventMineAppResponse response) { + return new EventMineResponse(response.eventId(), response.eventName(), response.isFinished(), response.createdAt()); + } +} diff --git a/server/src/main/java/server/haengdong/presentation/response/EventResponse.java b/server/src/main/java/haengdong/event/presentation/response/EventResponse.java similarity index 63% rename from server/src/main/java/server/haengdong/presentation/response/EventResponse.java rename to server/src/main/java/haengdong/event/presentation/response/EventResponse.java index 506f5e814..2f02454b9 100644 --- a/server/src/main/java/server/haengdong/presentation/response/EventResponse.java +++ b/server/src/main/java/haengdong/event/presentation/response/EventResponse.java @@ -1,6 +1,6 @@ -package server.haengdong.presentation.response; +package haengdong.event.presentation.response; -import server.haengdong.application.response.EventAppResponse; +import haengdong.event.application.response.EventAppResponse; public record EventResponse(String eventId) { diff --git a/server/src/main/java/haengdong/event/presentation/response/EventsMineResponse.java b/server/src/main/java/haengdong/event/presentation/response/EventsMineResponse.java new file mode 100644 index 000000000..feca51f6a --- /dev/null +++ b/server/src/main/java/haengdong/event/presentation/response/EventsMineResponse.java @@ -0,0 +1,17 @@ +package haengdong.event.presentation.response; + +import haengdong.event.application.request.EventMineAppResponse; +import java.util.List; + +public record EventsMineResponse( + List events +) { + + public static EventsMineResponse of(List responses) { + List events = responses.stream() + .map(EventMineResponse::of) + .toList(); + + return new EventsMineResponse(events); + } +} diff --git a/server/src/main/java/server/haengdong/presentation/response/MemberBillReportResponse.java b/server/src/main/java/haengdong/event/presentation/response/MemberBillReportResponse.java similarity index 81% rename from server/src/main/java/server/haengdong/presentation/response/MemberBillReportResponse.java rename to server/src/main/java/haengdong/event/presentation/response/MemberBillReportResponse.java index 1ab22b83e..a0d4d7370 100644 --- a/server/src/main/java/server/haengdong/presentation/response/MemberBillReportResponse.java +++ b/server/src/main/java/haengdong/event/presentation/response/MemberBillReportResponse.java @@ -1,6 +1,6 @@ -package server.haengdong.presentation.response; +package haengdong.event.presentation.response; -import server.haengdong.application.response.MemberBillReportAppResponse; +import haengdong.event.application.response.MemberBillReportAppResponse; public record MemberBillReportResponse( Long memberId, diff --git a/server/src/main/java/server/haengdong/presentation/response/MemberBillReportsResponse.java b/server/src/main/java/haengdong/event/presentation/response/MemberBillReportsResponse.java similarity index 77% rename from server/src/main/java/server/haengdong/presentation/response/MemberBillReportsResponse.java rename to server/src/main/java/haengdong/event/presentation/response/MemberBillReportsResponse.java index d350c4009..28f44d69a 100644 --- a/server/src/main/java/server/haengdong/presentation/response/MemberBillReportsResponse.java +++ b/server/src/main/java/haengdong/event/presentation/response/MemberBillReportsResponse.java @@ -1,7 +1,7 @@ -package server.haengdong.presentation.response; +package haengdong.event.presentation.response; import java.util.List; -import server.haengdong.application.response.MemberBillReportAppResponse; +import haengdong.event.application.response.MemberBillReportAppResponse; public record MemberBillReportsResponse(List reports) { diff --git a/server/src/main/java/server/haengdong/presentation/response/MemberDepositResponse.java b/server/src/main/java/haengdong/event/presentation/response/MemberDepositResponse.java similarity index 71% rename from server/src/main/java/server/haengdong/presentation/response/MemberDepositResponse.java rename to server/src/main/java/haengdong/event/presentation/response/MemberDepositResponse.java index 26699bc72..e54687db7 100644 --- a/server/src/main/java/server/haengdong/presentation/response/MemberDepositResponse.java +++ b/server/src/main/java/haengdong/event/presentation/response/MemberDepositResponse.java @@ -1,6 +1,6 @@ -package server.haengdong.presentation.response; +package haengdong.event.presentation.response; -import server.haengdong.application.response.MemberDepositAppResponse; +import haengdong.event.application.response.MemberDepositAppResponse; public record MemberDepositResponse( Long id, diff --git a/server/src/main/java/server/haengdong/presentation/response/MemberResponse.java b/server/src/main/java/haengdong/event/presentation/response/MemberResponse.java similarity index 66% rename from server/src/main/java/server/haengdong/presentation/response/MemberResponse.java rename to server/src/main/java/haengdong/event/presentation/response/MemberResponse.java index 6b43d72ee..d96b58e4e 100644 --- a/server/src/main/java/server/haengdong/presentation/response/MemberResponse.java +++ b/server/src/main/java/haengdong/event/presentation/response/MemberResponse.java @@ -1,7 +1,7 @@ -package server.haengdong.presentation.response; +package haengdong.event.presentation.response; -import server.haengdong.application.response.LastBillMemberAppResponse; -import server.haengdong.application.response.MemberAppResponse; +import haengdong.event.application.response.LastBillMemberAppResponse; +import haengdong.event.application.response.MemberAppResponse; public record MemberResponse( Long id, diff --git a/server/src/main/java/server/haengdong/presentation/response/MemberSaveResponse.java b/server/src/main/java/haengdong/event/presentation/response/MemberSaveResponse.java similarity index 66% rename from server/src/main/java/server/haengdong/presentation/response/MemberSaveResponse.java rename to server/src/main/java/haengdong/event/presentation/response/MemberSaveResponse.java index 21a7e7969..61fb7e080 100644 --- a/server/src/main/java/server/haengdong/presentation/response/MemberSaveResponse.java +++ b/server/src/main/java/haengdong/event/presentation/response/MemberSaveResponse.java @@ -1,6 +1,6 @@ -package server.haengdong.presentation.response; +package haengdong.event.presentation.response; -import server.haengdong.application.response.MemberSaveAppResponse; +import haengdong.event.application.response.MemberSaveAppResponse; public record MemberSaveResponse( Long id, diff --git a/server/src/main/java/server/haengdong/presentation/response/MembersResponse.java b/server/src/main/java/haengdong/event/presentation/response/MembersResponse.java similarity index 64% rename from server/src/main/java/server/haengdong/presentation/response/MembersResponse.java rename to server/src/main/java/haengdong/event/presentation/response/MembersResponse.java index 333428761..99efb61e4 100644 --- a/server/src/main/java/server/haengdong/presentation/response/MembersResponse.java +++ b/server/src/main/java/haengdong/event/presentation/response/MembersResponse.java @@ -1,8 +1,7 @@ -package server.haengdong.presentation.response; +package haengdong.event.presentation.response; import java.util.List; -import server.haengdong.application.response.MemberDepositAppResponse; -import server.haengdong.application.response.MembersDepositAppResponse; +import haengdong.event.application.response.MembersDepositAppResponse; public record MembersResponse( List members diff --git a/server/src/main/java/server/haengdong/presentation/response/MembersSaveResponse.java b/server/src/main/java/haengdong/event/presentation/response/MembersSaveResponse.java similarity index 76% rename from server/src/main/java/server/haengdong/presentation/response/MembersSaveResponse.java rename to server/src/main/java/haengdong/event/presentation/response/MembersSaveResponse.java index d4b7ad456..4fddd814f 100644 --- a/server/src/main/java/server/haengdong/presentation/response/MembersSaveResponse.java +++ b/server/src/main/java/haengdong/event/presentation/response/MembersSaveResponse.java @@ -1,7 +1,7 @@ -package server.haengdong.presentation.response; +package haengdong.event.presentation.response; import java.util.List; -import server.haengdong.application.response.MembersSaveAppResponse; +import haengdong.event.application.response.MembersSaveAppResponse; public record MembersSaveResponse( List members diff --git a/server/src/main/java/server/haengdong/presentation/response/StepResponse.java b/server/src/main/java/haengdong/event/presentation/response/StepResponse.java similarity index 82% rename from server/src/main/java/server/haengdong/presentation/response/StepResponse.java rename to server/src/main/java/haengdong/event/presentation/response/StepResponse.java index a164e71f5..6a7293462 100644 --- a/server/src/main/java/server/haengdong/presentation/response/StepResponse.java +++ b/server/src/main/java/haengdong/event/presentation/response/StepResponse.java @@ -1,7 +1,7 @@ -package server.haengdong.presentation.response; +package haengdong.event.presentation.response; import java.util.List; -import server.haengdong.application.response.StepAppResponse; +import haengdong.event.application.response.StepAppResponse; public record StepResponse( List bills, diff --git a/server/src/main/java/server/haengdong/presentation/response/StepsResponse.java b/server/src/main/java/haengdong/event/presentation/response/StepsResponse.java similarity index 71% rename from server/src/main/java/server/haengdong/presentation/response/StepsResponse.java rename to server/src/main/java/haengdong/event/presentation/response/StepsResponse.java index 8a66df1c6..ff9a23702 100644 --- a/server/src/main/java/server/haengdong/presentation/response/StepsResponse.java +++ b/server/src/main/java/haengdong/event/presentation/response/StepsResponse.java @@ -1,7 +1,7 @@ -package server.haengdong.presentation.response; +package haengdong.event.presentation.response; import java.util.List; -import server.haengdong.application.response.StepAppResponse; +import haengdong.event.application.response.StepAppResponse; public record StepsResponse( List steps diff --git a/server/src/main/java/haengdong/event/properties/ImageProperties.java b/server/src/main/java/haengdong/event/properties/ImageProperties.java new file mode 100644 index 000000000..8d62f63cc --- /dev/null +++ b/server/src/main/java/haengdong/event/properties/ImageProperties.java @@ -0,0 +1,11 @@ +package haengdong.event.properties; + +import org.springframework.boot.context.properties.ConfigurationProperties; + +@ConfigurationProperties("image") +public record ImageProperties( + String bucket, + String directory, + String baseUrl +) { +} diff --git a/server/src/main/java/haengdong/user/application/KakaoClient.java b/server/src/main/java/haengdong/user/application/KakaoClient.java new file mode 100644 index 000000000..b6c5c7ab2 --- /dev/null +++ b/server/src/main/java/haengdong/user/application/KakaoClient.java @@ -0,0 +1,49 @@ +package haengdong.user.application; + +import haengdong.common.exception.HaengdongErrorCode; +import haengdong.common.exception.HaengdongException; +import haengdong.user.application.response.KakaoTokenResponse; +import haengdong.user.config.KakaoProperties; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.springframework.boot.context.properties.EnableConfigurationProperties; +import org.springframework.http.HttpHeaders; +import org.springframework.http.MediaType; +import org.springframework.stereotype.Component; +import org.springframework.util.LinkedMultiValueMap; +import org.springframework.util.MultiValueMap; +import org.springframework.web.client.RestClient; + +@Slf4j +@RequiredArgsConstructor +@EnableConfigurationProperties(KakaoProperties.class) +@Component +public class KakaoClient { + + private final KakaoProperties kakaoProperties; + private final RestClient restClient; + + public KakaoTokenResponse join(String code, String redirectUri) { + MultiValueMap params = new LinkedMultiValueMap<>(); + params.add("grant_type", "authorization_code"); + params.add("client_id", kakaoProperties.clientId()); + params.add("redirect_uri", redirectUri); + params.add("code", code); + + try { + return restClient.post() + .uri(kakaoProperties.baseUri() + kakaoProperties.tokenRequestUri()) + .header(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_FORM_URLENCODED_VALUE) + .body(params) + .retrieve() + .body(KakaoTokenResponse.class); + } catch (Exception e) { + log.info("로그인 실패 : {}", code); + throw new HaengdongException(HaengdongErrorCode.KAKAO_LOGIN_FAIL, e); + } + } + + public String getClientId() { + return kakaoProperties.clientId(); + } +} diff --git a/server/src/main/java/haengdong/user/application/KakaoUserService.java b/server/src/main/java/haengdong/user/application/KakaoUserService.java new file mode 100644 index 000000000..43119de78 --- /dev/null +++ b/server/src/main/java/haengdong/user/application/KakaoUserService.java @@ -0,0 +1,36 @@ +package haengdong.user.application; + +import com.auth0.jwt.JWT; +import com.auth0.jwt.interfaces.DecodedJWT; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.springframework.stereotype.Service; +import haengdong.user.application.response.KakaoTokenResponse; + +@Slf4j +@RequiredArgsConstructor +@Service +public class KakaoUserService { + + private static final String NICKNAME_KEY = "nickname"; + + private final UserService userService; + private final KakaoClient kakaoClient; + + public Long joinByKakao(String code, String redirectUri) { + KakaoTokenResponse kakaoToken = kakaoClient.join(code, redirectUri); + String idToken = kakaoToken.idToken(); + DecodedJWT decodedJWT = JWT.decode(idToken); + + String memberNumber = decodedJWT.getSubject(); + String nickname = decodedJWT.getClaim(NICKNAME_KEY).asString(); + + log.info("로그인 성공 : {}, {}, {}", code, memberNumber, nickname); + + return userService.join(memberNumber, nickname); + } + + public String getClientId() { + return kakaoClient.getClientId(); + } +} diff --git a/server/src/main/java/haengdong/user/application/UserService.java b/server/src/main/java/haengdong/user/application/UserService.java new file mode 100644 index 000000000..0e12f97cc --- /dev/null +++ b/server/src/main/java/haengdong/user/application/UserService.java @@ -0,0 +1,80 @@ +package haengdong.user.application; + +import haengdong.common.exception.AuthenticationException; +import haengdong.common.exception.HaengdongErrorCode; +import haengdong.common.exception.HaengdongException; +import haengdong.event.application.response.UserAppResponse; +import haengdong.user.application.request.UserGuestSaveAppRequest; +import haengdong.user.application.request.UserUpdateAppRequest; +import haengdong.user.domain.User; +import haengdong.user.domain.repository.UserRepository; +import lombok.RequiredArgsConstructor; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +@RequiredArgsConstructor +@Service +public class UserService { + private final UserRepository userRepository; + + private final KakaoClient kakaoClient; + + @Transactional + public Long joinGuest(UserGuestSaveAppRequest request) { + User user = request.toUser(); + + User savedUser = userRepository.save(user); + return savedUser.getId(); + } + + @Transactional + public Long join(String memberNumber, String nickname) { + User user = userRepository.findByMemberNumber(memberNumber) + .orElseGet(() -> userRepository.save(User.createMember(nickname, memberNumber))); + + return user.getId(); + } + + @Transactional(readOnly = true) + public void validateUser(Long id, String password) { + User user = getUser(id); + + if (user.isPasswordMismatch(password)) { + throw new AuthenticationException(HaengdongErrorCode.PASSWORD_INVALID); + } + } + + @Transactional + public void updateUser(UserUpdateAppRequest request) { + User user = getUser(request.id()); + + if (request.isNicknameExist()) { + user.changeNickname(request.nickname()); + } + if (request.isAccountExist()) { + user.changeAccount(request.bankName(), request.accountNumber()); + } + } + + @Transactional(readOnly = true) + public String findNicknameById(Long id) { + User user = getUser(id); + return user.getNickname(); + } + + @Transactional + public void withdraw(Long id) { + userRepository.deleteById(id); + } + + public UserAppResponse findById(Long id) { + User user = getUser(id); + + return UserAppResponse.of(user); + } + + private User getUser(Long id) { + return userRepository.findById(id) + .orElseThrow(() -> new HaengdongException(HaengdongErrorCode.PASSWORD_INVALID)); + } +} diff --git a/server/src/main/java/haengdong/user/application/request/UserGuestSaveAppRequest.java b/server/src/main/java/haengdong/user/application/request/UserGuestSaveAppRequest.java new file mode 100644 index 000000000..b6ba00503 --- /dev/null +++ b/server/src/main/java/haengdong/user/application/request/UserGuestSaveAppRequest.java @@ -0,0 +1,17 @@ +package haengdong.user.application.request; + +import jakarta.validation.constraints.NotBlank; +import haengdong.user.domain.User; + +public record UserGuestSaveAppRequest( + + @NotBlank(message = "닉네임은 공백일 수 없습니다.") + String nickname, + + @NotBlank(message = "비밀번호는 공백일 수 없습니다.") + String password +) { + public User toUser() { + return User.createGuest(nickname, password); + } +} diff --git a/server/src/main/java/haengdong/user/application/request/UserUpdateAppRequest.java b/server/src/main/java/haengdong/user/application/request/UserUpdateAppRequest.java new file mode 100644 index 000000000..c04ae2465 --- /dev/null +++ b/server/src/main/java/haengdong/user/application/request/UserUpdateAppRequest.java @@ -0,0 +1,17 @@ +package haengdong.user.application.request; + +public record UserUpdateAppRequest( + Long id, + String nickname, + String bankName, + String accountNumber +) { + public boolean isNicknameExist() { + return nickname != null && !nickname.isBlank(); + } + + public boolean isAccountExist() { + return accountNumber != null && !accountNumber.isBlank() + && bankName != null && !bankName.isBlank(); + } +} diff --git a/server/src/main/java/haengdong/user/application/response/KakaoTokenResponse.java b/server/src/main/java/haengdong/user/application/response/KakaoTokenResponse.java new file mode 100644 index 000000000..f379a03c6 --- /dev/null +++ b/server/src/main/java/haengdong/user/application/response/KakaoTokenResponse.java @@ -0,0 +1,12 @@ +package haengdong.user.application.response; + +import com.fasterxml.jackson.annotation.JsonProperty; + +public record KakaoTokenResponse( + @JsonProperty("access_token") + String accessToken, + + @JsonProperty("id_token") + String idToken +) { +} diff --git a/server/src/main/java/haengdong/user/config/KakaoConfig.java b/server/src/main/java/haengdong/user/config/KakaoConfig.java new file mode 100644 index 000000000..4c70bdbf2 --- /dev/null +++ b/server/src/main/java/haengdong/user/config/KakaoConfig.java @@ -0,0 +1,34 @@ +package haengdong.user.config; + +import java.time.Duration; +import org.springframework.boot.web.client.ClientHttpRequestFactories; +import org.springframework.boot.web.client.ClientHttpRequestFactorySettings; +import org.springframework.boot.web.client.RestClientCustomizer; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.http.client.ClientHttpRequestFactory; +import org.springframework.http.client.JdkClientHttpRequestFactory; +import org.springframework.web.client.RestClient; + +@Configuration +public class KakaoConfig { + + @Bean + public RestClient restClient(RestClient.Builder restClientBuilder) { + return restClientBuilder.build(); + } + + @Bean + public RestClientCustomizer restClientCustomizer() { + return restClientBuilder -> restClientBuilder + .requestFactory(clientHttpRequestFactory()); + } + + private ClientHttpRequestFactory clientHttpRequestFactory() { + ClientHttpRequestFactorySettings settings = ClientHttpRequestFactorySettings.DEFAULTS + .withConnectTimeout(Duration.ofSeconds(3L)) + .withReadTimeout(Duration.ofSeconds(30L)); + + return ClientHttpRequestFactories.get(JdkClientHttpRequestFactory.class, settings); + } +} diff --git a/server/src/main/java/haengdong/user/config/KakaoProperties.java b/server/src/main/java/haengdong/user/config/KakaoProperties.java new file mode 100644 index 000000000..0e9bff45c --- /dev/null +++ b/server/src/main/java/haengdong/user/config/KakaoProperties.java @@ -0,0 +1,12 @@ +package haengdong.user.config; + +import org.springframework.boot.context.properties.ConfigurationProperties; + +@ConfigurationProperties("kakao") +public record KakaoProperties( + String baseUri, + String clientId, + String tokenRequestUri, + String oauthCodeUri +) { +} diff --git a/server/src/main/java/server/haengdong/domain/event/Bank.java b/server/src/main/java/haengdong/user/domain/Bank.java similarity index 91% rename from server/src/main/java/server/haengdong/domain/event/Bank.java rename to server/src/main/java/haengdong/user/domain/Bank.java index 53fbbd92d..d033aea8c 100644 --- a/server/src/main/java/server/haengdong/domain/event/Bank.java +++ b/server/src/main/java/haengdong/user/domain/Bank.java @@ -1,8 +1,8 @@ -package server.haengdong.domain.event; +package haengdong.user.domain; import java.util.Arrays; -import server.haengdong.exception.HaengdongErrorCode; -import server.haengdong.exception.HaengdongException; +import haengdong.common.exception.HaengdongErrorCode; +import haengdong.common.exception.HaengdongException; public enum Bank { WOORI_BANK("우리은행"), diff --git a/server/src/main/java/haengdong/user/domain/Role.java b/server/src/main/java/haengdong/user/domain/Role.java new file mode 100644 index 000000000..0bb1a4df8 --- /dev/null +++ b/server/src/main/java/haengdong/user/domain/Role.java @@ -0,0 +1,5 @@ +package haengdong.user.domain; + +public enum Role { + GUEST, MEMBER +} diff --git a/server/src/main/java/haengdong/user/domain/User.java b/server/src/main/java/haengdong/user/domain/User.java new file mode 100644 index 000000000..a8c04edd3 --- /dev/null +++ b/server/src/main/java/haengdong/user/domain/User.java @@ -0,0 +1,104 @@ +package haengdong.user.domain; + +import haengdong.event.domain.event.Password; +import jakarta.persistence.AttributeOverride; +import jakarta.persistence.Column; +import jakarta.persistence.Embedded; +import jakarta.persistence.Entity; +import jakarta.persistence.GeneratedValue; +import jakarta.persistence.GenerationType; +import jakarta.persistence.Id; +import jakarta.persistence.Table; +import lombok.AccessLevel; +import lombok.Getter; +import lombok.NoArgsConstructor; +import haengdong.common.domain.BaseEntity; +import haengdong.common.exception.HaengdongErrorCode; +import haengdong.common.exception.HaengdongException; + +@Getter +@NoArgsConstructor(access = AccessLevel.PROTECTED) +@Table(name = "users") +@Entity +public class User extends BaseEntity { + + private static final int MIN_ACCOUNT_NUMBER_LENGTH = 8; + private static final int MAX_ACCOUNT_NUMBER_LENGTH = 30; + private static final int MIN_NICK_NAME_LENGTH = 1; + private static final int MAX_NICK_NAME_LENGTH = 8; + + @Id + @GeneratedValue(strategy = GenerationType.IDENTITY) + private Long id; + + @Column(nullable = false) + private String nickname; + + @Embedded + @AttributeOverride(name = "value", column = @Column(name = "password")) + private Password password; + + private String bank; + + @Column(length = MAX_ACCOUNT_NUMBER_LENGTH) + private String accountNumber; + + @Column(unique = true) + private String memberNumber; + + private User(String nickname, String password, String bank, String accountNumber, String memberNumber) { + this.nickname = nickname; + this.password = new Password(password); + this.bank = bank; + this.accountNumber = accountNumber; + this.memberNumber = memberNumber; + } + + public static User createGuest(String nickName, String password) { + return new User(nickName, password, "", "", null); + } + + public static User createMember(String nickName, String memberNumber) { + return new User(nickName, "0000", "", "", memberNumber); + } + + public void changeNickname(String nickname) { + validateNickname(nickname); + this.nickname = nickname; + } + + private void validateNickname(String nickname) { + int nicknameLength = nickname.trim().length(); + if (nicknameLength < MIN_NICK_NAME_LENGTH || MAX_NICK_NAME_LENGTH < nicknameLength) { + throw new HaengdongException( + HaengdongErrorCode.USER_NICK_NAME_LENGTH_INVALID, MIN_NICK_NAME_LENGTH, MAX_NICK_NAME_LENGTH); + } + } + + public void changeAccount(String bankName, String accountNumber) { + validateBankName(bankName); + validateAccountNumber(accountNumber); + this.bank = bankName; + this.accountNumber = accountNumber; + } + + private void validateBankName(String bankName) { + Bank.isExists(bankName); + } + + private void validateAccountNumber(String accountNumber) { + int accountLength = accountNumber.trim().length(); + if (accountLength < MIN_ACCOUNT_NUMBER_LENGTH || MAX_ACCOUNT_NUMBER_LENGTH < accountLength) { + throw new HaengdongException( + HaengdongErrorCode.ACCOUNT_LENGTH_INVALID, MIN_ACCOUNT_NUMBER_LENGTH, MAX_ACCOUNT_NUMBER_LENGTH); + } + } + + public boolean isPasswordMismatch(String rawPassword) { + return !password.matches(rawPassword); + } + + public boolean isGuest() { + return memberNumber == null || memberNumber.isBlank(); + } +} diff --git a/server/src/main/java/haengdong/user/domain/repository/UserRepository.java b/server/src/main/java/haengdong/user/domain/repository/UserRepository.java new file mode 100644 index 000000000..b0d214f09 --- /dev/null +++ b/server/src/main/java/haengdong/user/domain/repository/UserRepository.java @@ -0,0 +1,10 @@ +package haengdong.user.domain.repository; + +import java.util.Optional; +import org.springframework.data.jpa.repository.JpaRepository; +import haengdong.user.domain.User; + +public interface UserRepository extends JpaRepository { + + Optional findByMemberNumber(String memberNumber); +} diff --git a/server/src/main/java/haengdong/user/presentation/UserController.java b/server/src/main/java/haengdong/user/presentation/UserController.java new file mode 100644 index 000000000..76c418f41 --- /dev/null +++ b/server/src/main/java/haengdong/user/presentation/UserController.java @@ -0,0 +1,83 @@ +package haengdong.user.presentation; + +import jakarta.validation.Valid; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.springframework.boot.context.properties.EnableConfigurationProperties; +import org.springframework.http.HttpHeaders; +import org.springframework.http.ResponseCookie; +import org.springframework.http.ResponseEntity; +import org.springframework.stereotype.Controller; +import org.springframework.web.bind.annotation.DeleteMapping; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.PatchMapping; +import org.springframework.web.bind.annotation.RequestBody; +import org.springframework.web.bind.annotation.RequestParam; +import haengdong.common.auth.application.AuthService; +import haengdong.user.application.KakaoUserService; +import haengdong.user.application.UserService; +import haengdong.common.auth.Login; +import haengdong.common.properties.CookieProperties; +import haengdong.user.presentation.request.UserUpdateRequest; +import haengdong.user.presentation.response.KakaoClientId; + +@Slf4j +@RequiredArgsConstructor +@EnableConfigurationProperties(CookieProperties.class) +@Controller +public class UserController { + + private final UserService userService; + private final KakaoUserService kakaoUserService; + private final AuthService authService; + private final CookieProperties cookieProperties; + + @PatchMapping("/api/users") + public ResponseEntity updateUser( + @Login Long userId, + @Valid @RequestBody UserUpdateRequest request + ) { + userService.updateUser(request.toAppRequest(userId)); + return ResponseEntity.ok().build(); + } + + @GetMapping("/api/kakao-client-id") + public ResponseEntity getKakaoClientId() { + String clientId = kakaoUserService.getClientId(); + KakaoClientId kakaoClientId = new KakaoClientId(clientId); + + return ResponseEntity.ok(kakaoClientId); + } + + @GetMapping("/api/login/kakao") + public ResponseEntity kakaoLogin( + @RequestParam String code, + @RequestParam("redirect_uri") String redirectUri + ) { + log.info("Kakao login code, redirectUri: {}, {}", code, redirectUri); + Long userId = kakaoUserService.joinByKakao(code, redirectUri); + String jwtToken = authService.createGuestToken(userId); + + ResponseCookie responseCookie = createResponseCookie(jwtToken); + return ResponseEntity.ok() + .header(HttpHeaders.SET_COOKIE, responseCookie.toString()) + .build(); + } + + @DeleteMapping("/api/users") + public ResponseEntity deleteUser(@Login Long userId) { + userService.withdraw(userId); + return ResponseEntity.ok().build(); + } + + private ResponseCookie createResponseCookie(String token) { + return ResponseCookie.from(authService.getTokenName(), token) + .httpOnly(cookieProperties.httpOnly()) + .secure(cookieProperties.secure()) + .domain(cookieProperties.domain()) + .path(cookieProperties.path()) + .sameSite(cookieProperties.sameSite()) + .maxAge(cookieProperties.maxAge()) + .build(); + } +} diff --git a/server/src/main/java/haengdong/user/presentation/request/UserGuestSaveRequest.java b/server/src/main/java/haengdong/user/presentation/request/UserGuestSaveRequest.java new file mode 100644 index 000000000..d097a8270 --- /dev/null +++ b/server/src/main/java/haengdong/user/presentation/request/UserGuestSaveRequest.java @@ -0,0 +1,17 @@ +package haengdong.user.presentation.request; + +import jakarta.validation.constraints.NotBlank; +import haengdong.user.application.request.UserGuestSaveAppRequest; + +public record UserGuestSaveRequest( + + @NotBlank(message = "닉네임은 공백일 수 없습니다.") + String nickname, + + @NotBlank(message = "비밀번호는 공백일 수 없습니다.") + String password +) { + public UserGuestSaveAppRequest toAppRequest() { + return new UserGuestSaveAppRequest(nickname, password); + } +} diff --git a/server/src/main/java/haengdong/user/presentation/request/UserUpdateRequest.java b/server/src/main/java/haengdong/user/presentation/request/UserUpdateRequest.java new file mode 100644 index 000000000..ee6923de4 --- /dev/null +++ b/server/src/main/java/haengdong/user/presentation/request/UserUpdateRequest.java @@ -0,0 +1,13 @@ +package haengdong.user.presentation.request; + +import haengdong.user.application.request.UserUpdateAppRequest; + +public record UserUpdateRequest( + String nickname, + String bankName, + String accountNumber +) { + public UserUpdateAppRequest toAppRequest(Long userId) { + return new UserUpdateAppRequest(userId, nickname, bankName, accountNumber); + } +} diff --git a/server/src/main/java/haengdong/user/presentation/response/KakaoClientId.java b/server/src/main/java/haengdong/user/presentation/response/KakaoClientId.java new file mode 100644 index 000000000..61f89ad94 --- /dev/null +++ b/server/src/main/java/haengdong/user/presentation/response/KakaoClientId.java @@ -0,0 +1,6 @@ +package haengdong.user.presentation.response; + +public record KakaoClientId( + String clientId +) { +} diff --git a/server/src/main/java/server/haengdong/application/AuthService.java b/server/src/main/java/server/haengdong/application/AuthService.java deleted file mode 100644 index d9352ad53..000000000 --- a/server/src/main/java/server/haengdong/application/AuthService.java +++ /dev/null @@ -1,41 +0,0 @@ -package server.haengdong.application; - - -import java.util.Map; -import server.haengdong.domain.TokenProvider; -import server.haengdong.exception.AuthenticationException; -import server.haengdong.exception.HaengdongErrorCode; - -public class AuthService { - - private static final String TOKEN_NAME = "eventToken"; - private static final String CLAIM_SUB = "sub"; - - private final TokenProvider tokenProvider; - - public AuthService(TokenProvider tokenProvider) { - this.tokenProvider = tokenProvider; - } - - public String createToken(String eventId) { - Map payload = Map.of(CLAIM_SUB, eventId); - - return tokenProvider.createToken(payload); - } - - public String findEventIdByToken(String token) { - validateToken(token); - Map payload = tokenProvider.getPayload(token); - return (String) payload.get(CLAIM_SUB); - } - - private void validateToken(String token) { - if (!tokenProvider.validateToken(token)) { - throw new AuthenticationException(HaengdongErrorCode.TOKEN_INVALID); - } - } - - public String getTokenName() { - return TOKEN_NAME; - } -} diff --git a/server/src/main/java/server/haengdong/application/BillService.java b/server/src/main/java/server/haengdong/application/BillService.java deleted file mode 100644 index 407914d29..000000000 --- a/server/src/main/java/server/haengdong/application/BillService.java +++ /dev/null @@ -1,155 +0,0 @@ -package server.haengdong.application; - -import java.util.List; -import lombok.RequiredArgsConstructor; -import org.springframework.stereotype.Service; -import org.springframework.transaction.annotation.Transactional; -import server.haengdong.application.request.BillAppRequest; -import server.haengdong.application.request.BillDetailUpdateAppRequest; -import server.haengdong.application.request.BillDetailsUpdateAppRequest; -import server.haengdong.application.request.BillUpdateAppRequest; -import server.haengdong.application.response.BillDetailsAppResponse; -import server.haengdong.application.response.StepAppResponse; -import server.haengdong.domain.bill.Bill; -import server.haengdong.domain.bill.BillDetail; -import server.haengdong.domain.bill.BillRepository; -import server.haengdong.domain.event.Event; -import server.haengdong.domain.event.EventRepository; -import server.haengdong.domain.member.Member; -import server.haengdong.domain.member.MemberRepository; -import server.haengdong.domain.step.Steps; -import server.haengdong.exception.HaengdongErrorCode; -import server.haengdong.exception.HaengdongException; - -@RequiredArgsConstructor -@Transactional(readOnly = true) -@Service -public class BillService { - - private final BillRepository billRepository; - private final EventRepository eventRepository; - private final MemberRepository memberRepository; - - @Transactional - public void saveBill(String eventToken, BillAppRequest request) { - Event event = getEvent(eventToken); - List memberIds = request.memberIds(); - List members = memberIds.stream() - .map(this::findMember) - .toList(); - - Bill bill = request.toBill(event, members); - billRepository.save(bill); - } - - private Member findMember(Long memberId) { - return memberRepository.findById(memberId) - .orElseThrow(() -> new HaengdongException(HaengdongErrorCode.MEMBER_NOT_FOUND)); - } - - public List findSteps(String token) { - Event event = getEvent(token); - List bills = billRepository.findAllByEvent(event); - - return createStepAppResponses(bills); - } - - private List createStepAppResponses(List bills) { - Steps steps = Steps.of(bills); - return steps.getSteps().stream() - .map(StepAppResponse::of) - .toList(); - } - - @Transactional - public void updateBill(String token, Long billId, BillUpdateAppRequest request) { - Bill bill = getBill(billId); - - validateToken(token, bill); - - bill.update(request.title(), request.price()); - } - - private void validateToken(String token, Bill bill) { - Event event = bill.getEvent(); - if (event.isTokenMismatch(token)) { - throw new HaengdongException(HaengdongErrorCode.BILL_NOT_FOUND); - } - } - - @Transactional - public void deleteBill(String token, Long billId) { - Bill bill = getBill(billId); - validateToken(token, bill); - billRepository.deleteById(billId); - } - - public BillDetailsAppResponse findBillDetails(String token, Long billId) { - Bill bill = billRepository.findById(billId) - .orElseThrow(() -> new HaengdongException(HaengdongErrorCode.BILL_NOT_FOUND)); - validateToken(token, bill); - - List billDetails = bill.getBillDetails(); - return BillDetailsAppResponse.of(billDetails); - } - - @Transactional - public void updateBillDetails(String token, Long billId, BillDetailsUpdateAppRequest request) { - Bill bill = billRepository.findById(billId) - .orElseThrow(() -> new HaengdongException(HaengdongErrorCode.BILL_NOT_FOUND)); - - List billDetailUpdateAppRequests = request.billDetailUpdateAppRequests(); - - validateToken(token, bill); - validateBillDetailSize(billDetailUpdateAppRequests, bill); - validateTotalPrice(billDetailUpdateAppRequests, bill); - - List billDetails = bill.getBillDetails(); - - for (BillDetailUpdateAppRequest updateRequest : billDetailUpdateAppRequests) { - BillDetail detailToUpdate = billDetails.stream() - .filter(detail -> detail.isSameId(updateRequest.id())) - .findFirst() - .orElseThrow(() -> new HaengdongException(HaengdongErrorCode.BILL_DETAIL_NOT_FOUND)); - - detailToUpdate.updatePrice(updateRequest.price()); - detailToUpdate.updateIsFixed(updateRequest.isFixed()); - } - } - - private void validateBillDetailSize(List requests, Bill bill) { - List ids = requests.stream() - .map(BillDetailUpdateAppRequest::id) - .distinct() - .toList(); - if (bill.getBillDetails().size() != ids.size()) { - throw new HaengdongException(HaengdongErrorCode.BILL_DETAIL_NOT_FOUND); - } - } - - private void validateTotalPrice( - List billDetailUpdateAppRequests, - Bill bill - ) { - Long requestsPriceSum = calculateUpdatePriceSum(billDetailUpdateAppRequests); - if (!bill.isSamePrice(requestsPriceSum)) { - throw new HaengdongException(HaengdongErrorCode.BILL_PRICE_NOT_MATCHED); - } - } - - private Long calculateUpdatePriceSum(List billDetailUpdateAppRequests) { - return billDetailUpdateAppRequests.stream() - .map(BillDetailUpdateAppRequest::price) - .reduce(0L, Long::sum); - } - - private Event getEvent(String eventToken) { - return eventRepository.findByToken(eventToken) - .orElseThrow(() -> new HaengdongException(HaengdongErrorCode.EVENT_NOT_FOUND)); - } - - private Bill getBill(Long billId) { - return billRepository.findById(billId) - .orElseThrow(() -> new HaengdongException(HaengdongErrorCode.BILL_NOT_FOUND)); - } -} diff --git a/server/src/main/java/server/haengdong/application/MemberService.java b/server/src/main/java/server/haengdong/application/MemberService.java deleted file mode 100644 index 840c4f769..000000000 --- a/server/src/main/java/server/haengdong/application/MemberService.java +++ /dev/null @@ -1,118 +0,0 @@ -package server.haengdong.application; - - -import java.util.List; -import java.util.Set; -import lombok.RequiredArgsConstructor; -import org.springframework.stereotype.Service; -import org.springframework.transaction.annotation.Transactional; -import server.haengdong.application.request.MemberSaveAppRequest; -import server.haengdong.application.request.MembersSaveAppRequest; -import server.haengdong.application.request.MembersUpdateAppRequest; -import server.haengdong.application.response.MemberAppResponse; -import server.haengdong.application.response.MembersDepositAppResponse; -import server.haengdong.application.response.MembersSaveAppResponse; -import server.haengdong.domain.bill.Bill; -import server.haengdong.domain.bill.BillRepository; -import server.haengdong.domain.event.Event; -import server.haengdong.domain.event.EventRepository; -import server.haengdong.domain.member.Member; -import server.haengdong.domain.member.MemberRepository; -import server.haengdong.domain.member.UpdatedMembers; -import server.haengdong.exception.HaengdongErrorCode; -import server.haengdong.exception.HaengdongException; - -@RequiredArgsConstructor -@Transactional(readOnly = true) -@Service -public class MemberService { - - private final MemberRepository memberRepository; - private final EventRepository eventRepository; - private final BillRepository billRepository; - - @Transactional - public MembersSaveAppResponse saveMembers(String token, MembersSaveAppRequest request) { - Event event = getEvent(token); - List memberNames = request.members().stream() - .map(MemberSaveAppRequest::name) - .toList(); - - validateMemberSave(memberNames, event); - - List members = memberNames.stream() - .map(name -> new Member(event, name)) - .toList(); - - List savedMembers = memberRepository.saveAll(members); - return MembersSaveAppResponse.of(savedMembers); - } - - private void validateMemberSave(List memberNames, Event event) { - Set uniqueMemberNames = Set.copyOf(memberNames); - if (memberNames.size() != uniqueMemberNames.size()) { - throw new HaengdongException(HaengdongErrorCode.MEMBER_NAME_DUPLICATE, memberNames); - } - if (isDuplicatedMemberNames(uniqueMemberNames, event)) { - throw new HaengdongException(HaengdongErrorCode.MEMBER_ALREADY_EXIST); - } - } - - private boolean isDuplicatedMemberNames(Set uniqueMemberNames, Event event) { - return memberRepository.findAllByEvent(event).stream() - .anyMatch(member -> uniqueMemberNames.contains(member.getName())); - } - - public List getCurrentMembers(String token) { - Event event = getEvent(token); - - return billRepository.findFirstByEventOrderByIdDesc(event) - .map(Bill::getMembers) - .orElseGet(() -> memberRepository.findAllByEvent(event)) - .stream() - .map(MemberAppResponse::of) - .toList(); - } - - public MembersDepositAppResponse findAllMembers(String token) { - Event event = getEvent(token); - - List members = memberRepository.findAllByEvent(event); - - return MembersDepositAppResponse.of(members); - } - - @Transactional - public void updateMembers(String token, MembersUpdateAppRequest request) { - Event event = getEvent(token); - UpdatedMembers updatedMembers = new UpdatedMembers(request.toMembers(event)); - List originMembers = memberRepository.findAllByEvent(event); - - updatedMembers.validateUpdatable(originMembers); - memberRepository.saveAll(updatedMembers.getMembers()); - } - - @Transactional - public void deleteMember(String token, Long memberId) { - memberRepository.findById(memberId) - .ifPresent(member -> deleteMember(token, member)); - } - - private void deleteMember(String token, Member member) { - Event event = member.getEvent(); - if (event.isTokenMismatch(token)) { - throw new HaengdongException(HaengdongErrorCode.MEMBER_NOT_FOUND); - } - - billRepository.findAllByEvent(event).stream() - .filter(bill -> bill.containMember(member)) - .forEach(bill -> bill.removeMemberBillDetail(member)); - billRepository.flush(); - memberRepository.delete(member); - } - - private Event getEvent(String token) { - return eventRepository.findByToken(token) - .orElseThrow(() -> new HaengdongException(HaengdongErrorCode.EVENT_NOT_FOUND)); - } -} diff --git a/server/src/main/java/server/haengdong/application/request/BillAppRequest.java b/server/src/main/java/server/haengdong/application/request/BillAppRequest.java deleted file mode 100644 index 8eb945263..000000000 --- a/server/src/main/java/server/haengdong/application/request/BillAppRequest.java +++ /dev/null @@ -1,17 +0,0 @@ -package server.haengdong.application.request; - -import java.util.List; -import server.haengdong.domain.bill.Bill; -import server.haengdong.domain.member.Member; -import server.haengdong.domain.event.Event; - -public record BillAppRequest( - String title, - Long price, - List memberIds -) { - - public Bill toBill(Event event, List members) { - return Bill.create(event, title, price, members); - } -} diff --git a/server/src/main/java/server/haengdong/application/request/BillDetailUpdateAppRequest.java b/server/src/main/java/server/haengdong/application/request/BillDetailUpdateAppRequest.java deleted file mode 100644 index 4e66b9215..000000000 --- a/server/src/main/java/server/haengdong/application/request/BillDetailUpdateAppRequest.java +++ /dev/null @@ -1,8 +0,0 @@ -package server.haengdong.application.request; - -public record BillDetailUpdateAppRequest( - Long id, - Long price, - boolean isFixed -) { -} diff --git a/server/src/main/java/server/haengdong/application/request/BillDetailsUpdateAppRequest.java b/server/src/main/java/server/haengdong/application/request/BillDetailsUpdateAppRequest.java deleted file mode 100644 index 7a6477e08..000000000 --- a/server/src/main/java/server/haengdong/application/request/BillDetailsUpdateAppRequest.java +++ /dev/null @@ -1,8 +0,0 @@ -package server.haengdong.application.request; - -import java.util.List; - -public record BillDetailsUpdateAppRequest( - List billDetailUpdateAppRequests -) { -} diff --git a/server/src/main/java/server/haengdong/application/request/EventAppRequest.java b/server/src/main/java/server/haengdong/application/request/EventAppRequest.java deleted file mode 100644 index 20ec16d88..000000000 --- a/server/src/main/java/server/haengdong/application/request/EventAppRequest.java +++ /dev/null @@ -1,10 +0,0 @@ -package server.haengdong.application.request; - -import server.haengdong.domain.event.Event; - -public record EventAppRequest(String name, String password) { - - public Event toEvent(String token) { - return new Event(name, password, token); - } -} diff --git a/server/src/main/java/server/haengdong/application/request/EventUpdateAppRequest.java b/server/src/main/java/server/haengdong/application/request/EventUpdateAppRequest.java deleted file mode 100644 index 13bffccc1..000000000 --- a/server/src/main/java/server/haengdong/application/request/EventUpdateAppRequest.java +++ /dev/null @@ -1,17 +0,0 @@ -package server.haengdong.application.request; - -public record EventUpdateAppRequest( - String eventName, - String bankName, - String accountNumber -) { - - public boolean isEventNameExist() { - return eventName != null && !eventName.trim().isEmpty(); - } - - public boolean isAccountExist() { - return bankName != null && !bankName.trim().isEmpty() - && accountNumber != null && !accountNumber.trim().isEmpty(); - } -} diff --git a/server/src/main/java/server/haengdong/application/request/MemberUpdateAppRequest.java b/server/src/main/java/server/haengdong/application/request/MemberUpdateAppRequest.java deleted file mode 100644 index 77df0625b..000000000 --- a/server/src/main/java/server/haengdong/application/request/MemberUpdateAppRequest.java +++ /dev/null @@ -1,16 +0,0 @@ -package server.haengdong.application.request; - - -import server.haengdong.domain.member.Member; -import server.haengdong.domain.event.Event; - -public record MemberUpdateAppRequest( - Long id, - String name, - boolean isDeposited -) { - - public Member toMember(Event event) { - return new Member(id, event, name, isDeposited); - } -} diff --git a/server/src/main/java/server/haengdong/application/request/MembersSaveAppRequest.java b/server/src/main/java/server/haengdong/application/request/MembersSaveAppRequest.java deleted file mode 100644 index ae0c9fc62..000000000 --- a/server/src/main/java/server/haengdong/application/request/MembersSaveAppRequest.java +++ /dev/null @@ -1,8 +0,0 @@ -package server.haengdong.application.request; - -import java.util.List; - -public record MembersSaveAppRequest( - List members -) { -} diff --git a/server/src/main/java/server/haengdong/application/response/EventAppResponse.java b/server/src/main/java/server/haengdong/application/response/EventAppResponse.java deleted file mode 100644 index f331d0011..000000000 --- a/server/src/main/java/server/haengdong/application/response/EventAppResponse.java +++ /dev/null @@ -1,10 +0,0 @@ -package server.haengdong.application.response; - -import server.haengdong.domain.event.Event; - -public record EventAppResponse(String token) { - - public static EventAppResponse of(Event event) { - return new EventAppResponse(event.getToken()); - } -} diff --git a/server/src/main/java/server/haengdong/application/response/EventDetailAppResponse.java b/server/src/main/java/server/haengdong/application/response/EventDetailAppResponse.java deleted file mode 100644 index 899ea76ec..000000000 --- a/server/src/main/java/server/haengdong/application/response/EventDetailAppResponse.java +++ /dev/null @@ -1,14 +0,0 @@ -package server.haengdong.application.response; - -import server.haengdong.domain.event.Event; - -public record EventDetailAppResponse( - String eventName, - String bankName, - String accountNumber -) { - - public static EventDetailAppResponse of(Event event) { - return new EventDetailAppResponse(event.getName(), event.getBankName(), event.getAccountNumber()); - } -} diff --git a/server/src/main/java/server/haengdong/application/response/EventImageAppResponse.java b/server/src/main/java/server/haengdong/application/response/EventImageAppResponse.java deleted file mode 100644 index 26e442403..000000000 --- a/server/src/main/java/server/haengdong/application/response/EventImageAppResponse.java +++ /dev/null @@ -1,7 +0,0 @@ -package server.haengdong.application.response; - -public record EventImageAppResponse( - Long id, - String url -) { -} diff --git a/server/src/main/java/server/haengdong/application/response/LastBillMemberAppResponse.java b/server/src/main/java/server/haengdong/application/response/LastBillMemberAppResponse.java deleted file mode 100644 index abefe009a..000000000 --- a/server/src/main/java/server/haengdong/application/response/LastBillMemberAppResponse.java +++ /dev/null @@ -1,10 +0,0 @@ -package server.haengdong.application.response; - -import server.haengdong.domain.member.Member; - -public record LastBillMemberAppResponse(Long id, String name) { - - public static LastBillMemberAppResponse of(Member member) { - return new LastBillMemberAppResponse(member.getId(), member.getName()); - } -} diff --git a/server/src/main/java/server/haengdong/application/response/MemberAppResponse.java b/server/src/main/java/server/haengdong/application/response/MemberAppResponse.java deleted file mode 100644 index 98579b2d1..000000000 --- a/server/src/main/java/server/haengdong/application/response/MemberAppResponse.java +++ /dev/null @@ -1,13 +0,0 @@ -package server.haengdong.application.response; - -import server.haengdong.domain.member.Member; - -public record MemberAppResponse( - Long id, - String name -) { - - public static MemberAppResponse of(Member member) { - return new MemberAppResponse(member.getId(), member.getName()); - } -} diff --git a/server/src/main/java/server/haengdong/application/response/MemberDepositAppResponse.java b/server/src/main/java/server/haengdong/application/response/MemberDepositAppResponse.java deleted file mode 100644 index bb09e02df..000000000 --- a/server/src/main/java/server/haengdong/application/response/MemberDepositAppResponse.java +++ /dev/null @@ -1,14 +0,0 @@ -package server.haengdong.application.response; - -import server.haengdong.domain.member.Member; - -public record MemberDepositAppResponse( - Long id, - String name, - boolean isDeposited -) { - - public static MemberDepositAppResponse of(Member member) { - return new MemberDepositAppResponse(member.getId(), member.getName(), member.isDeposited()); - } -} diff --git a/server/src/main/java/server/haengdong/application/response/MemberSaveAppResponse.java b/server/src/main/java/server/haengdong/application/response/MemberSaveAppResponse.java deleted file mode 100644 index bd1d117f2..000000000 --- a/server/src/main/java/server/haengdong/application/response/MemberSaveAppResponse.java +++ /dev/null @@ -1,13 +0,0 @@ -package server.haengdong.application.response; - -import server.haengdong.domain.member.Member; - -public record MemberSaveAppResponse( - Long id, - String name -) { - - public static MemberSaveAppResponse of(Member member) { - return new MemberSaveAppResponse(member.getId(), member.getName()); - } -} diff --git a/server/src/main/java/server/haengdong/application/response/MembersDepositAppResponse.java b/server/src/main/java/server/haengdong/application/response/MembersDepositAppResponse.java deleted file mode 100644 index 007904d25..000000000 --- a/server/src/main/java/server/haengdong/application/response/MembersDepositAppResponse.java +++ /dev/null @@ -1,15 +0,0 @@ -package server.haengdong.application.response; - -import java.util.List; -import server.haengdong.domain.member.Member; - -public record MembersDepositAppResponse( - List members -) { - - public static MembersDepositAppResponse of(List members) { - return new MembersDepositAppResponse(members.stream() - .map(MemberDepositAppResponse::of) - .toList()); - } -} diff --git a/server/src/main/java/server/haengdong/config/S3Config.java b/server/src/main/java/server/haengdong/config/S3Config.java deleted file mode 100644 index cdac7c1dc..000000000 --- a/server/src/main/java/server/haengdong/config/S3Config.java +++ /dev/null @@ -1,26 +0,0 @@ -package server.haengdong.config; - -import java.util.concurrent.ExecutorService; -import java.util.concurrent.Executors; -import org.springframework.context.annotation.Bean; -import org.springframework.context.annotation.Configuration; -import software.amazon.awssdk.regions.Region; -import software.amazon.awssdk.services.s3.S3Client; - -@Configuration -public class S3Config { - - private static final int THREAD_POOL_SIZE = 10; - - @Bean - public S3Client s3Client() { - return S3Client.builder() - .region(Region.AP_NORTHEAST_2) - .build(); - } - - @Bean - public ExecutorService executorService() { - return Executors.newFixedThreadPool(THREAD_POOL_SIZE); - } -} diff --git a/server/src/main/java/server/haengdong/config/WebMvcConfig.java b/server/src/main/java/server/haengdong/config/WebMvcConfig.java deleted file mode 100644 index 43f858db3..000000000 --- a/server/src/main/java/server/haengdong/config/WebMvcConfig.java +++ /dev/null @@ -1,65 +0,0 @@ -package server.haengdong.config; - -import lombok.RequiredArgsConstructor; -import org.springframework.beans.factory.annotation.Value; -import org.springframework.boot.context.properties.EnableConfigurationProperties; -import org.springframework.context.annotation.Bean; -import org.springframework.context.annotation.Configuration; -import org.springframework.web.servlet.config.annotation.CorsRegistry; -import org.springframework.web.servlet.config.annotation.InterceptorRegistry; -import org.springframework.web.servlet.config.annotation.WebMvcConfigurer; -import server.haengdong.application.AuthService; -import server.haengdong.domain.TokenProvider; -import server.haengdong.infrastructure.auth.AuthenticationExtractor; -import server.haengdong.infrastructure.auth.JwtTokenProvider; -import server.haengdong.infrastructure.auth.TokenProperties; - -@RequiredArgsConstructor -@EnableConfigurationProperties(TokenProperties.class) -@Configuration -public class WebMvcConfig implements WebMvcConfigurer { - - private final TokenProperties tokenProperties; - - @Value("${cors.max-age}") - private Long maxAge; - - @Value("${cors.allowed-origins}") - private String[] allowedOrigins; - - @Override - public void addCorsMappings(CorsRegistry registry) { - registry.addMapping("/**") - .allowedOrigins(allowedOrigins) - .allowedMethods("GET", "POST", "PUT", "PATCH", "DELETE", "OPTIONS") - .allowedHeaders("*") - .allowCredentials(true) - .maxAge(maxAge); - } - - @Override - public void addInterceptors(InterceptorRegistry registry) { - registry.addInterceptor(adminInterceptor()) - .addPathPatterns("/api/admin/**"); - } - - @Bean - public AdminInterceptor adminInterceptor() { - return new AdminInterceptor(authService(), authenticationExtractor()); - } - - @Bean - public AuthService authService() { - return new AuthService(tokenProvider()); - } - - @Bean - public TokenProvider tokenProvider() { - return new JwtTokenProvider(tokenProperties); - } - - @Bean - public AuthenticationExtractor authenticationExtractor() { - return new AuthenticationExtractor(); - } -} diff --git a/server/src/main/java/server/haengdong/domain/bill/MemberBillReport.java b/server/src/main/java/server/haengdong/domain/bill/MemberBillReport.java deleted file mode 100644 index ee16824d0..000000000 --- a/server/src/main/java/server/haengdong/domain/bill/MemberBillReport.java +++ /dev/null @@ -1,30 +0,0 @@ -package server.haengdong.domain.bill; - -import static java.util.stream.Collectors.toMap; - -import java.util.List; -import java.util.Map; -import lombok.Getter; -import server.haengdong.domain.member.Member; - -@Getter -public class MemberBillReport { - - private final Map reports; - - private MemberBillReport(Map reports) { - this.reports = reports; - } - - public static MemberBillReport createByBills(List bills) { - Map reports = bills.stream() - .flatMap(bill -> bill.getBillDetails().stream()) - .collect(toMap( - BillDetail::getMember, - BillDetail::getPrice, - Long::sum - )); - - return new MemberBillReport(reports); - } -} diff --git a/server/src/main/java/server/haengdong/domain/member/MemberRepository.java b/server/src/main/java/server/haengdong/domain/member/MemberRepository.java deleted file mode 100644 index 15d57f4ba..000000000 --- a/server/src/main/java/server/haengdong/domain/member/MemberRepository.java +++ /dev/null @@ -1,10 +0,0 @@ -package server.haengdong.domain.member; - -import java.util.List; -import org.springframework.data.jpa.repository.JpaRepository; -import server.haengdong.domain.event.Event; - -public interface MemberRepository extends JpaRepository { - - List findAllByEvent(Event event); -} diff --git a/server/src/main/java/server/haengdong/domain/member/UpdatedMembers.java b/server/src/main/java/server/haengdong/domain/member/UpdatedMembers.java deleted file mode 100644 index 3a588c077..000000000 --- a/server/src/main/java/server/haengdong/domain/member/UpdatedMembers.java +++ /dev/null @@ -1,67 +0,0 @@ -package server.haengdong.domain.member; - -import java.util.HashSet; -import java.util.List; -import java.util.Set; -import java.util.stream.Collectors; -import server.haengdong.exception.HaengdongErrorCode; -import server.haengdong.exception.HaengdongException; - -public class UpdatedMembers { - - private final Set members; - - public UpdatedMembers(List members) { - validateMemberUnique(members); - validateNameUnique(members); - this.members = new HashSet<>(members); - } - - private void validateMemberUnique(List members) { - if (members.size() != Set.copyOf(members).size()) { - throw new HaengdongException(HaengdongErrorCode.MEMBER_NAME_CHANGE_DUPLICATE); - } - } - - private void validateNameUnique(List members) { - Set uniqueNames = members.stream() - .map(Member::getName) - .collect(Collectors.toSet()); - if (members.size() != uniqueNames.size()) { - throw new HaengdongException(HaengdongErrorCode.MEMBER_NAME_CHANGE_DUPLICATE); - } - } - - public void validateUpdatable(List originMembers) { - Set uniqueMembers = Set.copyOf(originMembers); - validateUpdatedMembersExist(uniqueMembers); - validateUpdatedNamesUnique(uniqueMembers); - } - - private void validateUpdatedMembersExist(Set originMembers) { - if (!this.members.equals(originMembers)) { - throw new HaengdongException(HaengdongErrorCode.MEMBER_UPDATE_MISMATCH); - } - } - - private void validateUpdatedNamesUnique(Set originMembers) { - boolean duplicated = originMembers.stream() - .anyMatch(this::isMemberNameUpdated); - - if (duplicated) { - throw new HaengdongException(HaengdongErrorCode.MEMBER_NAME_DUPLICATE); - } - } - - private boolean isMemberNameUpdated(Member originMembers) { - return this.members.stream() - .filter(member -> !member.getId().equals(originMembers.getId())) - .anyMatch(member -> member.hasName(originMembers.getName())); - } - - public List getMembers() { - return members.stream().toList(); - } -} - - diff --git a/server/src/main/java/server/haengdong/domain/step/Step.java b/server/src/main/java/server/haengdong/domain/step/Step.java deleted file mode 100644 index 834d3e715..000000000 --- a/server/src/main/java/server/haengdong/domain/step/Step.java +++ /dev/null @@ -1,50 +0,0 @@ -package server.haengdong.domain.step; - -import java.util.ArrayList; -import java.util.HashSet; -import java.util.List; -import java.util.Set; -import server.haengdong.domain.bill.Bill; -import server.haengdong.domain.member.Member; -import server.haengdong.exception.HaengdongErrorCode; -import server.haengdong.exception.HaengdongException; - -public class Step { - - private final List bills; - private final Set members; - - private Step(List bills, Set members) { - this.bills = bills; - this.members = members; - } - - public static Step of(Bill bill) { - List bills = new ArrayList<>(); - bills.add(bill); - Set members = new HashSet<>(bill.getMembers()); - - return new Step(bills, members); - } - - public void add(Bill bill) { - if (isNotSameMember(bill)) { - throw new HaengdongException(HaengdongErrorCode.DIFFERENT_STEP_MEMBERS); - } - - bills.add(bill); - } - - public boolean isNotSameMember(Bill bill) { - Set otherMembers = Set.copyOf(bill.getMembers()); - return !members.equals(otherMembers); - } - - public List getBills() { - return bills; - } - - public Set getMembers() { - return members; - } -} diff --git a/server/src/main/java/server/haengdong/presentation/request/EventSaveRequest.java b/server/src/main/java/server/haengdong/presentation/request/EventSaveRequest.java deleted file mode 100644 index 6bd7cd006..000000000 --- a/server/src/main/java/server/haengdong/presentation/request/EventSaveRequest.java +++ /dev/null @@ -1,18 +0,0 @@ -package server.haengdong.presentation.request; - -import jakarta.validation.constraints.NotBlank; -import server.haengdong.application.request.EventAppRequest; - -public record EventSaveRequest( - - @NotBlank(message = "행사 이름은 공백일 수 없습니다.") - String eventName, - - @NotBlank(message = "비밀번호는 공백일 수 없습니다.") - String password -) { - - public EventAppRequest toAppRequest() { - return new EventAppRequest(eventName, password); - } -} diff --git a/server/src/main/java/server/haengdong/presentation/request/EventUpdateRequest.java b/server/src/main/java/server/haengdong/presentation/request/EventUpdateRequest.java deleted file mode 100644 index cafd12ea6..000000000 --- a/server/src/main/java/server/haengdong/presentation/request/EventUpdateRequest.java +++ /dev/null @@ -1,14 +0,0 @@ -package server.haengdong.presentation.request; - -import server.haengdong.application.request.EventUpdateAppRequest; - -public record EventUpdateRequest( - String eventName, - String bankName, - String accountNumber -) { - - public EventUpdateAppRequest toAppRequest() { - return new EventUpdateAppRequest(eventName, bankName, accountNumber); - } -} diff --git a/server/src/main/java/server/haengdong/presentation/response/EventDetailResponse.java b/server/src/main/java/server/haengdong/presentation/response/EventDetailResponse.java deleted file mode 100644 index e5421940c..000000000 --- a/server/src/main/java/server/haengdong/presentation/response/EventDetailResponse.java +++ /dev/null @@ -1,14 +0,0 @@ -package server.haengdong.presentation.response; - -import server.haengdong.application.response.EventDetailAppResponse; - -public record EventDetailResponse( - String eventName, - String bankName, - String accountNumber -) { - - public static EventDetailResponse of(EventDetailAppResponse response) { - return new EventDetailResponse(response.eventName(), response.bankName(), response.accountNumber()); - } -} diff --git a/server/src/main/java/server/haengdong/presentation/response/EventImageResponse.java b/server/src/main/java/server/haengdong/presentation/response/EventImageResponse.java deleted file mode 100644 index da807655f..000000000 --- a/server/src/main/java/server/haengdong/presentation/response/EventImageResponse.java +++ /dev/null @@ -1,13 +0,0 @@ -package server.haengdong.presentation.response; - -import server.haengdong.application.response.EventImageAppResponse; - -public record EventImageResponse( - Long id, - String url -) { - - public static EventImageResponse of(EventImageAppResponse response) { - return new EventImageResponse(response.id(), response.url()); - } -} diff --git a/server/src/main/resources/application.yml b/server/src/main/resources/application.yml index e3d8d5e8a..9c3673065 100644 --- a/server/src/main/resources/application.yml +++ b/server/src/main/resources/application.yml @@ -9,6 +9,9 @@ spring: max-file-size: 50MB max-request-size: 300MB + lifecycle: + timeout-per-shutdown-phase: "10s" + h2: console: enabled: true @@ -42,9 +45,9 @@ cookie: max-age: 7D image: - bucket: techcourse-project-2024 - directory: haeng-dong/s3-upload-test/ - base-url: https://d2unln22cedgp9.cloudfront.net/ + bucket: haeng-dong + directory: image/ + base-url: https://d3a4djq153056h.cloudfront.net/ management: endpoints: @@ -69,6 +72,14 @@ server: enabled: true threads: max: 50 + shutdown: graceful + +kakao: + base-uri: https://kauth.kakao.com + token-request-uri: /oauth/token + client-id: 52f24834ff7304ed2c47294b3f57b053 + oauth-code-uri: https://kauth.kakao.com/oauth/authorize?client_id=%s&redirect_uri=%s&response_type=code&scope=openid + --- spring: diff --git a/server/src/main/resources/config b/server/src/main/resources/config index f7a9ac8ef..00d38ce60 160000 --- a/server/src/main/resources/config +++ b/server/src/main/resources/config @@ -1 +1 @@ -Subproject commit f7a9ac8efafd2bd87f53acc53a133a6933e3a7d8 +Subproject commit 00d38ce60ba6f4543a80d23e37dc28a48070c15b diff --git a/server/src/test/java/server/haengdong/application/BillServiceTest.java b/server/src/test/java/haengdong/application/BillServiceTest.java similarity index 65% rename from server/src/test/java/server/haengdong/application/BillServiceTest.java rename to server/src/test/java/haengdong/application/BillServiceTest.java index 6d2b7aa8d..1dff0da75 100644 --- a/server/src/test/java/server/haengdong/application/BillServiceTest.java +++ b/server/src/test/java/haengdong/application/BillServiceTest.java @@ -1,4 +1,4 @@ -package server.haengdong.application; +package haengdong.application; import static org.assertj.core.api.Assertions.assertThat; import static org.assertj.core.api.Assertions.assertThatThrownBy; @@ -9,24 +9,25 @@ import org.junit.jupiter.api.DisplayName; import org.junit.jupiter.api.Test; import org.springframework.beans.factory.annotation.Autowired; -import server.haengdong.application.request.BillAppRequest; -import server.haengdong.application.request.BillDetailUpdateAppRequest; -import server.haengdong.application.request.BillDetailsUpdateAppRequest; -import server.haengdong.application.request.BillUpdateAppRequest; -import server.haengdong.application.response.BillAppResponse; -import server.haengdong.application.response.BillDetailAppResponse; -import server.haengdong.application.response.BillDetailsAppResponse; -import server.haengdong.application.response.MemberAppResponse; -import server.haengdong.application.response.StepAppResponse; -import server.haengdong.domain.bill.Bill; -import server.haengdong.domain.bill.BillDetail; -import server.haengdong.domain.bill.BillRepository; -import server.haengdong.domain.event.Event; -import server.haengdong.domain.event.EventRepository; -import server.haengdong.domain.member.Member; -import server.haengdong.domain.member.MemberRepository; -import server.haengdong.exception.HaengdongException; -import server.haengdong.support.fixture.Fixture; +import haengdong.event.application.BillService; +import haengdong.event.application.request.BillAppRequest; +import haengdong.event.application.request.BillDetailUpdateAppRequest; +import haengdong.event.application.request.BillDetailsUpdateAppRequest; +import haengdong.event.application.request.BillUpdateAppRequest; +import haengdong.event.application.response.BillAppResponse; +import haengdong.event.application.response.BillDetailAppResponse; +import haengdong.event.application.response.BillDetailsAppResponse; +import haengdong.event.application.response.MemberAppResponse; +import haengdong.event.application.response.StepAppResponse; +import haengdong.event.domain.bill.Bill; +import haengdong.event.domain.bill.BillDetail; +import haengdong.event.domain.bill.BillRepository; +import haengdong.event.domain.event.Event; +import haengdong.event.domain.event.EventRepository; +import haengdong.event.domain.event.member.EventMember; +import haengdong.event.domain.event.member.EventMemberRepository; +import haengdong.common.exception.HaengdongException; +import haengdong.support.fixture.Fixture; class BillServiceTest extends ServiceTestSupport { @@ -40,22 +41,24 @@ class BillServiceTest extends ServiceTestSupport { private BillRepository billRepository; @Autowired - private MemberRepository memberRepository; + private EventMemberRepository eventMemberRepository; @DisplayName("전체 지출 내역을 조회한다.") @Test void findSteps() { Event event = Fixture.EVENT1; eventRepository.save(event); - Member member1 = new Member(event, "토다리"); - Member member2 = new Member(event, "쿠키"); - Member member3 = new Member(event, "소하"); - Member member4 = new Member(event, "웨디"); - memberRepository.saveAll(List.of(member1, member2, member3, member4)); - Bill bill1 = Bill.create(event, "행동대장 회식1", 100000L, List.of(member1, member2, member3)); - Bill bill2 = Bill.create(event, "행동대장 회식2", 200000L, List.of(member1, member2, member3, member4)); - Bill bill3 = Bill.create(event, "행동대장 회식3", 300000L, List.of(member1, member2, member3, member4)); - Bill bill4 = Bill.create(event, "행동대장 회식4", 400000L, List.of(member2, member3, member4)); + EventMember eventMember1 = new EventMember(event, "토다리"); + EventMember eventMember2 = new EventMember(event, "쿠키"); + EventMember eventMember3 = new EventMember(event, "소하"); + EventMember eventMember4 = new EventMember(event, "웨디"); + eventMemberRepository.saveAll(List.of(eventMember1, eventMember2, eventMember3, eventMember4)); + Bill bill1 = Bill.create(event, "행동대장 회식1", 100000L, List.of(eventMember1, eventMember2, eventMember3)); + Bill bill2 = Bill.create(event, "행동대장 회식2", 200000L, List.of( + eventMember1, eventMember2, eventMember3, eventMember4)); + Bill bill3 = Bill.create(event, "행동대장 회식3", 300000L, List.of( + eventMember1, eventMember2, eventMember3, eventMember4)); + Bill bill4 = Bill.create(event, "행동대장 회식4", 400000L, List.of(eventMember2, eventMember3, eventMember4)); billRepository.saveAll(List.of(bill1, bill2, bill3, bill4)); List steps = billService.findSteps(event.getToken()); @@ -72,9 +75,9 @@ void findSteps() { assertThat(steps.get(0).members()).hasSize(3) .extracting(MemberAppResponse::id, MemberAppResponse::name) .containsExactlyInAnyOrder( - tuple(member1.getId(), member1.getName()), - tuple(member2.getId(), member2.getName()), - tuple(member3.getId(), member3.getName()) + tuple(eventMember1.getId(), eventMember1.getName()), + tuple(eventMember2.getId(), eventMember2.getName()), + tuple(eventMember3.getId(), eventMember3.getName()) ); assertThat(steps.get(1).bills()).hasSize(2) @@ -88,10 +91,10 @@ void findSteps() { assertThat(steps.get(1).members()).hasSize(4) .extracting(MemberAppResponse::id, MemberAppResponse::name) .containsExactlyInAnyOrder( - tuple(member1.getId(), member1.getName()), - tuple(member2.getId(), member2.getName()), - tuple(member3.getId(), member3.getName()), - tuple(member4.getId(), member4.getName()) + tuple(eventMember1.getId(), eventMember1.getName()), + tuple(eventMember2.getId(), eventMember2.getName()), + tuple(eventMember3.getId(), eventMember3.getName()), + tuple(eventMember4.getId(), eventMember4.getName()) ); assertThat(steps.get(2).bills()).hasSize(1) @@ -104,9 +107,9 @@ void findSteps() { assertThat(steps.get(2).members()).hasSize(3) .extracting(MemberAppResponse::id, MemberAppResponse::name) .containsExactlyInAnyOrder( - tuple(member2.getId(), member2.getName()), - tuple(member3.getId(), member3.getName()), - tuple(member4.getId(), member4.getName()) + tuple(eventMember2.getId(), eventMember2.getName()), + tuple(eventMember3.getId(), eventMember3.getName()), + tuple(eventMember4.getId(), eventMember4.getName()) ); } @@ -116,10 +119,10 @@ void saveBill() { Event event = Fixture.EVENT1; Event savedEvent = eventRepository.save(event); - Member member1 = Fixture.MEMBER1; - Member member2 = Fixture.MEMBER2; - memberRepository.saveAll(List.of(member1, member2)); - List memberIds = List.of(member1.getId(), member2.getId()); + EventMember eventMember1 = Fixture.EVENT_MEMBER_1; + EventMember eventMember2 = Fixture.EVENT_MEMBER_2; + eventMemberRepository.saveAll(List.of(eventMember1, eventMember2)); + List memberIds = List.of(eventMember1.getId(), eventMember2.getId()); BillAppRequest billAppRequest = new BillAppRequest("뽕족", 10_000L, memberIds); billService.saveBill(event.getToken(), billAppRequest); @@ -138,12 +141,12 @@ void saveBillTest1() { Event event = Fixture.EVENT1; eventRepository.save(event); - Member member1 = Fixture.MEMBER1; - Member member2 = Fixture.MEMBER2; - List members = List.of(member1, member2); - memberRepository.saveAll(members); + EventMember eventMember1 = Fixture.EVENT_MEMBER_1; + EventMember eventMember2 = Fixture.EVENT_MEMBER_2; + List eventMembers = List.of(eventMember1, eventMember2); + eventMemberRepository.saveAll(eventMembers); - BillAppRequest request = new BillAppRequest("뽕족", 10_000L, List.of(member1.getId(), member2.getId())); + BillAppRequest request = new BillAppRequest("뽕족", 10_000L, List.of(eventMember1.getId(), eventMember2.getId())); billService.saveBill(event.getToken(), request); @@ -153,10 +156,10 @@ void saveBillTest1() { assertThat(billDetails) .hasSize(2) - .extracting("member", "price") + .extracting("eventMember", "price") .containsExactlyInAnyOrder( - tuple(member1, 5_000L), - tuple(member2, 5_000L) + tuple(eventMember1, 5_000L), + tuple(eventMember2, 5_000L) ); } @@ -166,12 +169,12 @@ void saveBill1() { Event event = Fixture.EVENT1; eventRepository.save(event); - Member member1 = Fixture.MEMBER1; - Member member2 = Fixture.MEMBER2; - List members = List.of(member1, member2); - memberRepository.saveAll(members); + EventMember eventMember1 = Fixture.EVENT_MEMBER_1; + EventMember eventMember2 = Fixture.EVENT_MEMBER_2; + List eventMembers = List.of(eventMember1, eventMember2); + eventMemberRepository.saveAll(eventMembers); - BillAppRequest request = new BillAppRequest("뽕족", 10_000L, List.of(member1.getId(), member2.getId())); + BillAppRequest request = new BillAppRequest("뽕족", 10_000L, List.of(eventMember1.getId(), eventMember2.getId())); assertThatThrownBy(() -> billService.saveBill("wrongToken", request)) .isInstanceOf(HaengdongException.class); @@ -222,13 +225,13 @@ void updateBill1() { void updateBill2() { Event event = Fixture.EVENT1; eventRepository.save(event); - Member member1 = new Member(event, "감자"); - Member member2 = new Member(event, "고구마"); - Member member3 = new Member(event, "당근"); - Member member4 = new Member(event, "양파"); - List members = List.of(member1, member2, member3, member4); - memberRepository.saveAll(members); - Bill bill = Bill.create(event, "뽕족", 10_000L, members); + EventMember eventMember1 = new EventMember(event, "감자"); + EventMember eventMember2 = new EventMember(event, "고구마"); + EventMember eventMember3 = new EventMember(event, "당근"); + EventMember eventMember4 = new EventMember(event, "양파"); + List eventMembers = List.of(eventMember1, eventMember2, eventMember3, eventMember4); + eventMemberRepository.saveAll(eventMembers); + Bill bill = Bill.create(event, "뽕족", 10_000L, eventMembers); bill.getBillDetails().forEach(billDetail -> billDetail.updateIsFixed(true)); billRepository.save(bill); BillUpdateAppRequest request = new BillUpdateAppRequest("인생맥주", 20_000L); @@ -248,11 +251,11 @@ void updateBill2() { void deleteBill() { Event event = Fixture.EVENT1; eventRepository.save(event); - Member member1 = new Member(event, "토다리"); - Member member2 = new Member(event, "쿠키"); - memberRepository.saveAll(List.of(member1, member2)); + EventMember eventMember1 = new EventMember(event, "토다리"); + EventMember eventMember2 = new EventMember(event, "쿠키"); + eventMemberRepository.saveAll(List.of(eventMember1, eventMember2)); - Bill bill = Bill.create(event, "뽕족", 10000L, List.of(member1, member2)); + Bill bill = Bill.create(event, "뽕족", 10000L, List.of(eventMember1, eventMember2)); billRepository.save(bill); Long billId = bill.getId(); @@ -273,11 +276,11 @@ void deleteBill1() { void updateBillDetailsTest1() { Event event1 = Fixture.EVENT1; eventRepository.save(event1); - Member member1 = new Member(event1, "토다리"); - Member member2 = new Member(event1, "쿠키"); - memberRepository.saveAll(List.of(member1, member2)); + EventMember eventMember1 = new EventMember(event1, "토다리"); + EventMember eventMember2 = new EventMember(event1, "쿠키"); + eventMemberRepository.saveAll(List.of(eventMember1, eventMember2)); - Bill bill = Bill.create(event1, "뽕족", 10000L, List.of(member1, member2)); + Bill bill = Bill.create(event1, "뽕족", 10000L, List.of(eventMember1, eventMember2)); billRepository.save(bill); List billDetails = bill.getBillDetails(); @@ -297,11 +300,11 @@ void updateBillDetailsTest1() { void updateBillDetailsTest2() { Event event1 = Fixture.EVENT1; eventRepository.save(event1); - Member member1 = new Member(event1, "토다리"); - Member member2 = new Member(event1, "쿠키"); - memberRepository.saveAll(List.of(member1, member2)); + EventMember eventMember1 = new EventMember(event1, "토다리"); + EventMember eventMember2 = new EventMember(event1, "쿠키"); + eventMemberRepository.saveAll(List.of(eventMember1, eventMember2)); - Bill bill = Bill.create(event1, "뽕족", 10000L, List.of(member1, member2)); + Bill bill = Bill.create(event1, "뽕족", 10000L, List.of(eventMember1, eventMember2)); billRepository.save(bill); List billDetails = bill.getBillDetails(); @@ -318,8 +321,8 @@ void updateBillDetailsTest2() { assertThat(foundBillDetails).hasSize(2) .extracting(BillDetail::getId, BillDetail::getPrice) .containsExactly( - tuple(billDetails.get(0).getId(), 3000L), - tuple(billDetails.get(1).getId(), 7000L) + tuple(3L, 3000L), + tuple(4L, 7000L) ); } @@ -329,12 +332,12 @@ void findBillDetailsTest() { Event event1 = Fixture.EVENT1; eventRepository.save(event1); - Member member1 = Fixture.MEMBER1; - Member member2 = Fixture.MEMBER2; - List members = List.of(member1, member2); - memberRepository.saveAll(members); + EventMember eventMember1 = Fixture.EVENT_MEMBER_1; + EventMember eventMember2 = Fixture.EVENT_MEMBER_2; + List eventMembers = List.of(eventMember1, eventMember2); + eventMemberRepository.saveAll(eventMembers); - Bill bill = Bill.create(event1, "뽕족", 10000L, members); + Bill bill = Bill.create(event1, "뽕족", 10000L, eventMembers); billRepository.save(bill); BillDetailsAppResponse response = billService.findBillDetails(event1.getToken(), bill.getId()); diff --git a/server/src/test/java/server/haengdong/application/MemberServiceTest.java b/server/src/test/java/haengdong/application/EventEventMemberServiceTest.java similarity index 51% rename from server/src/test/java/server/haengdong/application/MemberServiceTest.java rename to server/src/test/java/haengdong/application/EventEventMemberServiceTest.java index 662156a33..01e94e428 100644 --- a/server/src/test/java/server/haengdong/application/MemberServiceTest.java +++ b/server/src/test/java/haengdong/application/EventEventMemberServiceTest.java @@ -1,4 +1,4 @@ -package server.haengdong.application; +package haengdong.application; import static org.assertj.core.api.Assertions.assertThat; import static org.assertj.core.api.Assertions.assertThatThrownBy; @@ -6,43 +6,44 @@ import static org.junit.jupiter.api.Assertions.assertAll; import static org.junit.jupiter.api.Assertions.assertFalse; import static org.junit.jupiter.api.Assertions.assertTrue; -import static server.haengdong.support.fixture.Fixture.BILL1; -import static server.haengdong.support.fixture.Fixture.EVENT1; -import static server.haengdong.support.fixture.Fixture.EVENT2; -import static server.haengdong.support.fixture.Fixture.MEMBER1; -import static server.haengdong.support.fixture.Fixture.MEMBER2; -import static server.haengdong.support.fixture.Fixture.MEMBER3; +import static haengdong.support.fixture.Fixture.BILL1; +import static haengdong.support.fixture.Fixture.EVENT1; +import static haengdong.support.fixture.Fixture.EVENT2; +import static haengdong.support.fixture.Fixture.EVENT_MEMBER_1; +import static haengdong.support.fixture.Fixture.EVENT_MEMBER_2; +import static haengdong.support.fixture.Fixture.EVENT_MEMBER_3; import java.util.List; import org.assertj.core.groups.Tuple; import org.junit.jupiter.api.DisplayName; import org.junit.jupiter.api.Test; import org.springframework.beans.factory.annotation.Autowired; -import server.haengdong.application.request.MemberSaveAppRequest; -import server.haengdong.application.request.MemberUpdateAppRequest; -import server.haengdong.application.request.MembersSaveAppRequest; -import server.haengdong.application.request.MembersUpdateAppRequest; -import server.haengdong.application.response.MemberAppResponse; -import server.haengdong.application.response.MemberDepositAppResponse; -import server.haengdong.application.response.MemberSaveAppResponse; -import server.haengdong.application.response.MembersDepositAppResponse; -import server.haengdong.application.response.MembersSaveAppResponse; -import server.haengdong.domain.bill.Bill; -import server.haengdong.domain.bill.BillDetail; -import server.haengdong.domain.bill.BillRepository; -import server.haengdong.domain.event.Event; -import server.haengdong.domain.event.EventRepository; -import server.haengdong.domain.member.Member; -import server.haengdong.domain.member.MemberRepository; -import server.haengdong.exception.HaengdongException; - -class MemberServiceTest extends ServiceTestSupport { +import haengdong.event.application.EventMemberService; +import haengdong.event.application.request.MemberSaveAppRequest; +import haengdong.event.application.request.MemberUpdateAppRequest; +import haengdong.event.application.request.MembersSaveAppRequest; +import haengdong.event.application.request.MembersUpdateAppRequest; +import haengdong.event.application.response.MemberAppResponse; +import haengdong.event.application.response.MemberDepositAppResponse; +import haengdong.event.application.response.MemberSaveAppResponse; +import haengdong.event.application.response.MembersDepositAppResponse; +import haengdong.event.application.response.MembersSaveAppResponse; +import haengdong.event.domain.bill.Bill; +import haengdong.event.domain.bill.BillDetail; +import haengdong.event.domain.bill.BillRepository; +import haengdong.event.domain.event.Event; +import haengdong.event.domain.event.EventRepository; +import haengdong.event.domain.event.member.EventMember; +import haengdong.event.domain.event.member.EventMemberRepository; +import haengdong.common.exception.HaengdongException; + +class EventEventMemberServiceTest extends ServiceTestSupport { @Autowired - private MemberService memberService; + private EventMemberService eventMemberService; @Autowired - private MemberRepository memberRepository; + private EventMemberRepository eventMemberRepository; @Autowired private EventRepository eventRepository; @@ -56,22 +57,22 @@ void saveMembersTest() { Event event = EVENT1; String memberName1 = "웨디"; String memberName2 = "쿠키"; - Member member1 = new Member(event, memberName1); - Member member2 = new Member(event, memberName2); + EventMember eventMember1 = new EventMember(event, memberName1); + EventMember eventMember2 = new EventMember(event, memberName2); eventRepository.save(event); MembersSaveAppRequest request = new MembersSaveAppRequest( List.of( - new MemberSaveAppRequest(member1.getName()), - new MemberSaveAppRequest(member2.getName()) + new MemberSaveAppRequest(eventMember1.getName()), + new MemberSaveAppRequest(eventMember2.getName()) ) ); - MembersSaveAppResponse response = memberService.saveMembers(event.getToken(), request); + MembersSaveAppResponse response = eventMemberService.saveMembers(event.getToken(), request); - List savedMembers = memberRepository.findAll(); + List savedEventMembers = eventMemberRepository.findAll(); assertAll( - () -> assertThat(savedMembers) - .extracting(Member::getName) + () -> assertThat(savedEventMembers) + .extracting(EventMember::getName) .containsExactlyInAnyOrder(memberName1, memberName2), () -> assertThat(response.members()) .extracting(MemberSaveAppResponse::id, MemberSaveAppResponse::name) @@ -86,18 +87,18 @@ void saveMembersTest() { @Test void saveMembersTest1() { Event event = EVENT1; - Member member1 = MEMBER1; - Member member2 = MEMBER2; + EventMember eventMember1 = EVENT_MEMBER_1; + EventMember eventMember2 = EVENT_MEMBER_2; eventRepository.save(event); - memberRepository.save(member1); + eventMemberRepository.save(eventMember1); MembersSaveAppRequest request = new MembersSaveAppRequest( List.of( - new MemberSaveAppRequest(member1.getName()), - new MemberSaveAppRequest(member2.getName()) + new MemberSaveAppRequest(eventMember1.getName()), + new MemberSaveAppRequest(eventMember2.getName()) ) ); - assertThatThrownBy(() -> memberService.saveMembers(event.getToken(), request)) + assertThatThrownBy(() -> eventMemberService.saveMembers(event.getToken(), request)) .isInstanceOf(HaengdongException.class) .hasMessage("현재 참여하고 있는 인원이 존재합니다."); } @@ -114,7 +115,7 @@ void saveMembersTest2() { ) ); - assertThatThrownBy(() -> memberService.saveMembers(event.getToken(), request)) + assertThatThrownBy(() -> eventMemberService.saveMembers(event.getToken(), request)) .isInstanceOf(HaengdongException.class) .hasMessageContaining("행사에 중복된 참여자 이름이 존재합니다."); } @@ -123,13 +124,13 @@ void saveMembersTest2() { @Test void deleteMemberTest() { Event event = EVENT1; - Member member = MEMBER1; + EventMember eventMember = EVENT_MEMBER_1; eventRepository.save(event); - memberRepository.save(member); + eventMemberRepository.save(eventMember); - memberService.deleteMember(event.getToken(), member.getId()); + eventMemberService.deleteMember(event.getToken(), eventMember.getId()); - assertThat(memberRepository.findById(member.getId())).isEmpty(); + assertThat(eventMemberRepository.findById(eventMember.getId())).isEmpty(); } @DisplayName("다른 이벤트의 참여 인원을 삭제하는 경우 예외가 발생한다.") @@ -137,41 +138,41 @@ void deleteMemberTest() { void deleteMemberTest1() { Event event1 = EVENT1; Event event2 = EVENT2; - Member member = new Member(EVENT2, "감자"); + EventMember eventMember = new EventMember(EVENT2, "감자"); eventRepository.saveAll(List.of(event1, event2)); - memberRepository.save(member); + eventMemberRepository.save(eventMember); - assertThatThrownBy(() -> memberService.deleteMember(event1.getToken(), member.getId())) + assertThatThrownBy(() -> eventMemberService.deleteMember(event1.getToken(), eventMember.getId())) .isInstanceOf(HaengdongException.class); - assertThat(memberRepository.findById(member.getId())).isNotEmpty(); + assertThat(eventMemberRepository.findById(eventMember.getId())).isNotEmpty(); } @DisplayName("행사 참여 인원을 삭제하는 경우 해당 참여자가 포함된 Bill이 초기화된다.") @Test void deleteMemberTest2() { Event event1 = EVENT1; - Member member1 = MEMBER1; - Member member2 = MEMBER2; - List members = List.of(member1, member2); - Bill bill = Bill.create(event1, "title", 10000L, members); + EventMember eventMember1 = EVENT_MEMBER_1; + EventMember eventMember2 = EVENT_MEMBER_2; + List eventMembers = List.of(eventMember1, eventMember2); + Bill bill = Bill.create(event1, "title", 10000L, eventMembers); eventRepository.save(event1); - memberRepository.saveAll(members); + eventMemberRepository.saveAll(eventMembers); - BillDetail billDetail1 = getDetailByMember(bill, member1); - BillDetail billDetail2 = getDetailByMember(bill, member2); + BillDetail billDetail1 = getDetailByMember(bill, eventMember1); + BillDetail billDetail2 = getDetailByMember(bill, eventMember2); billDetail1.updatePrice(8000L); billDetail1.updateIsFixed(false); billDetail2.updatePrice(2000L); billDetail2.updateIsFixed(true); billRepository.save(bill); - memberService.deleteMember(event1.getToken(), member1.getId()); + eventMemberService.deleteMember(event1.getToken(), eventMember1.getId()); Bill bill1 = billRepository.findAllByEvent(event1).get(0); List bill1Details = bill1.getBillDetails(); assertAll( - () -> assertThat(memberRepository.findById(member1.getId())).isEmpty(), + () -> assertThat(eventMemberRepository.findById(eventMember1.getId())).isEmpty(), () -> assertThat(bill1Details).doesNotContain(billDetail1), () -> { BillDetail foundDetail = bill1Details.stream() @@ -182,10 +183,10 @@ void deleteMemberTest2() { ); } - private BillDetail getDetailByMember(Bill bill, Member member) { + private BillDetail getDetailByMember(Bill bill, EventMember eventMember) { return bill.getBillDetails() .stream() - .filter(billDetail -> billDetail.isMember(member)) + .filter(billDetail -> billDetail.isMember(eventMember)) .findFirst() .orElseThrow(); } @@ -194,21 +195,21 @@ private BillDetail getDetailByMember(Bill bill, Member member) { @Test void updateMembersNameTest() { Event event = EVENT1; - Member member = MEMBER1; + EventMember eventMember = EVENT_MEMBER_1; eventRepository.save(event); - memberRepository.save(member); + eventMemberRepository.save(eventMember); MembersUpdateAppRequest membersUpdateAppRequest = new MembersUpdateAppRequest( List.of( - new MemberUpdateAppRequest(member.getId(), "수정된이름", true) + new MemberUpdateAppRequest(eventMember.getId(), "수정된이름", true) ) ); - memberService.updateMembers(event.getToken(), membersUpdateAppRequest); + eventMemberService.updateMembers(event.getToken(), membersUpdateAppRequest); - Member updatedMember = memberRepository.findById(member.getId()).orElseThrow(); + EventMember updatedEventMember = eventMemberRepository.findById(eventMember.getId()).orElseThrow(); assertAll( - () -> assertThat(updatedMember.getName()).isEqualTo("수정된이름"), - () -> assertTrue(updatedMember.isDeposited()) + () -> assertThat(updatedEventMember.getName()).isEqualTo("수정된이름"), + () -> assertTrue(updatedEventMember.isDeposited()) ); } @@ -216,21 +217,21 @@ void updateMembersNameTest() { @Test void updateMembersIsDepositedTest() { Event event = EVENT1; - Member member = MEMBER1; + EventMember eventMember = EVENT_MEMBER_1; eventRepository.save(event); - memberRepository.save(member); + eventMemberRepository.save(eventMember); MembersUpdateAppRequest membersUpdateAppRequest = new MembersUpdateAppRequest( List.of( - new MemberUpdateAppRequest(member.getId(), member.getName(), false) + new MemberUpdateAppRequest(eventMember.getId(), eventMember.getName(), false) ) ); - memberService.updateMembers(event.getToken(), membersUpdateAppRequest); + eventMemberService.updateMembers(event.getToken(), membersUpdateAppRequest); - Member updatedMember = memberRepository.findById(member.getId()).orElseThrow(); + EventMember updatedEventMember = eventMemberRepository.findById(eventMember.getId()).orElseThrow(); assertAll( - () -> assertThat(updatedMember.getName()).isEqualTo(member.getName()), - () -> assertFalse(updatedMember.isDeposited()) + () -> assertThat(updatedEventMember.getName()).isEqualTo(eventMember.getName()), + () -> assertFalse(updatedEventMember.isDeposited()) ); } @@ -238,17 +239,17 @@ void updateMembersIsDepositedTest() { @Test void updateMembersTest2() { Event event = EVENT1; - Member member = MEMBER1; + EventMember eventMember = EVENT_MEMBER_1; eventRepository.save(event); - memberRepository.save(member); + eventMemberRepository.save(eventMember); MembersUpdateAppRequest membersUpdateAppRequest = new MembersUpdateAppRequest( List.of( - new MemberUpdateAppRequest(member.getId(), "수정", true), - new MemberUpdateAppRequest(member.getId(), "수정수정", false) + new MemberUpdateAppRequest(eventMember.getId(), "수정", true), + new MemberUpdateAppRequest(eventMember.getId(), "수정수정", false) ) ); - assertThatThrownBy(() -> memberService.updateMembers(event.getToken(), membersUpdateAppRequest)) + assertThatThrownBy(() -> eventMemberService.updateMembers(event.getToken(), membersUpdateAppRequest)) .isInstanceOf(HaengdongException.class) .hasMessage("중복된 참여 인원 이름 변경 요청이 존재합니다."); } @@ -257,18 +258,18 @@ void updateMembersTest2() { @Test void updateMembersTest3() { Event event = EVENT1; - Member member1 = MEMBER1; - Member member2 = MEMBER2; + EventMember eventMember1 = EVENT_MEMBER_1; + EventMember eventMember2 = EVENT_MEMBER_2; eventRepository.save(event); - memberRepository.saveAll(List.of(member1, member2)); + eventMemberRepository.saveAll(List.of(eventMember1, eventMember2)); MembersUpdateAppRequest membersUpdateAppRequest = new MembersUpdateAppRequest( List.of( - new MemberUpdateAppRequest(member1.getId(), "수정", true), - new MemberUpdateAppRequest(member2.getId(), "수정", false) + new MemberUpdateAppRequest(eventMember1.getId(), "수정", true), + new MemberUpdateAppRequest(eventMember2.getId(), "수정", false) ) ); - assertThatThrownBy(() -> memberService.updateMembers(event.getToken(), membersUpdateAppRequest)) + assertThatThrownBy(() -> eventMemberService.updateMembers(event.getToken(), membersUpdateAppRequest)) .isInstanceOf(HaengdongException.class) .hasMessage("중복된 참여 인원 이름 변경 요청이 존재합니다."); } @@ -278,16 +279,16 @@ void updateMembersTest3() { void updateMembersTest4() { Event event1 = EVENT1; Event event2 = EVENT2; - Member member = new Member(event2, "이상"); + EventMember eventMember = new EventMember(event2, "이상"); eventRepository.saveAll(List.of(event1, event2)); - memberRepository.save(member); + eventMemberRepository.save(eventMember); MembersUpdateAppRequest membersUpdateAppRequest = new MembersUpdateAppRequest( List.of( - new MemberUpdateAppRequest(member.getId(), "수정", true) + new MemberUpdateAppRequest(eventMember.getId(), "수정", true) ) ); - assertThatThrownBy(() -> memberService.updateMembers(event1.getToken(), membersUpdateAppRequest)) + assertThatThrownBy(() -> eventMemberService.updateMembers(event1.getToken(), membersUpdateAppRequest)) .isInstanceOf(HaengdongException.class) .hasMessage("업데이트 요청된 참여자 ID 목록과 기존 행사 참여자 ID 목록이 일치하지 않습니다."); } @@ -296,17 +297,17 @@ void updateMembersTest4() { @Test void updateMembersTest5() { Event event1 = EVENT1; - Member member1 = MEMBER1; - Member member2 = MEMBER2; + EventMember eventMember1 = EVENT_MEMBER_1; + EventMember eventMember2 = EVENT_MEMBER_2; eventRepository.save(event1); - memberRepository.saveAll(List.of(member1, member2)); + eventMemberRepository.saveAll(List.of(eventMember1, eventMember2)); MembersUpdateAppRequest membersUpdateAppRequest = new MembersUpdateAppRequest( List.of( - new MemberUpdateAppRequest(member1.getId(), member2.getName(), true) + new MemberUpdateAppRequest(eventMember1.getId(), eventMember2.getName(), true) ) ); - assertThatThrownBy(() -> memberService.updateMembers(event1.getToken(), membersUpdateAppRequest)) + assertThatThrownBy(() -> eventMemberService.updateMembers(event1.getToken(), membersUpdateAppRequest)) .isInstanceOf(HaengdongException.class) .hasMessage("업데이트 요청된 참여자 ID 목록과 기존 행사 참여자 ID 목록이 일치하지 않습니다."); } @@ -315,18 +316,18 @@ void updateMembersTest5() { @Test void updateMembersTest6() { Event event = EVENT1; - Member member1 = MEMBER1; - Member member2 = MEMBER2; + EventMember eventMember1 = EVENT_MEMBER_1; + EventMember eventMember2 = EVENT_MEMBER_2; eventRepository.save(event); - memberRepository.saveAll(List.of(member1, member2)); + eventMemberRepository.saveAll(List.of(eventMember1, eventMember2)); MembersUpdateAppRequest membersUpdateAppRequest = new MembersUpdateAppRequest( List.of( - new MemberUpdateAppRequest(member1.getId(), member2.getName(), true), - new MemberUpdateAppRequest(member2.getId(), member1.getName(), false) + new MemberUpdateAppRequest(eventMember1.getId(), eventMember2.getName(), true), + new MemberUpdateAppRequest(eventMember2.getId(), eventMember1.getName(), false) ) ); - assertThatThrownBy(() -> memberService.updateMembers(event.getToken(), membersUpdateAppRequest)) + assertThatThrownBy(() -> eventMemberService.updateMembers(event.getToken(), membersUpdateAppRequest)) .isInstanceOf(HaengdongException.class) .hasMessage("행사에 중복된 참여자 이름이 존재합니다."); } @@ -336,21 +337,21 @@ void updateMembersTest6() { void findAllMembersTest() { Event event = EVENT1; Bill bill = BILL1; - Member member1 = MEMBER1; - Member member2 = MEMBER2; - Member member3 = MEMBER3; + EventMember eventMember1 = EVENT_MEMBER_1; + EventMember eventMember2 = EVENT_MEMBER_2; + EventMember eventMember3 = EVENT_MEMBER_3; eventRepository.save(event); - memberRepository.saveAll(List.of(member1, member2, member3)); + eventMemberRepository.saveAll(List.of(eventMember1, eventMember2, eventMember3)); billRepository.save(bill); - MembersDepositAppResponse membersDepositAppResponse = memberService.findAllMembers(event.getToken()); + MembersDepositAppResponse membersDepositAppResponse = eventMemberService.findAllMembers(event.getToken()); assertThat(membersDepositAppResponse.members()).hasSize(3) .extracting(MemberDepositAppResponse::name, MemberDepositAppResponse::isDeposited) .containsExactlyInAnyOrder( - tuple(member1.getName(), member1.isDeposited()), - tuple(member2.getName(), member2.isDeposited()), - tuple(member3.getName(), member3.isDeposited()) + tuple(eventMember1.getName(), eventMember1.isDeposited()), + tuple(eventMember2.getName(), eventMember2.isDeposited()), + tuple(eventMember3.getName(), eventMember3.isDeposited()) ); } @@ -358,31 +359,31 @@ void findAllMembersTest() { @Test void getCurrentMembersTest() { Event event = EVENT1; - Member member1 = MEMBER1; - Member member2 = MEMBER2; - Member member3 = MEMBER3; - Bill bill1 = Bill.create(event, "title1", 100000L, List.of(member1)); - Bill bill2 = Bill.create(event, "title2", 200000L, List.of(member1, member2, member3)); - Bill bill3 = Bill.create(event, "title2", 200000L, List.of(member1, member2, member3)); + EventMember eventMember1 = EVENT_MEMBER_1; + EventMember eventMember2 = EVENT_MEMBER_2; + EventMember eventMember3 = EVENT_MEMBER_3; + Bill bill1 = Bill.create(event, "title1", 100000L, List.of(eventMember1)); + Bill bill2 = Bill.create(event, "title2", 200000L, List.of(eventMember1, eventMember2, eventMember3)); + Bill bill3 = Bill.create(event, "title2", 200000L, List.of(eventMember1, eventMember2, eventMember3)); eventRepository.save(event); - memberRepository.saveAll(List.of(member1, member2, member3)); + eventMemberRepository.saveAll(List.of(eventMember1, eventMember2, eventMember3)); billRepository.saveAll(List.of(bill1, bill2, bill3)); - List currentMembers = memberService.getCurrentMembers(event.getToken()); + List currentMembers = eventMemberService.getCurrentMembers(event.getToken()); assertThat(currentMembers).hasSize(3) .extracting(MemberAppResponse::id, MemberAppResponse::name) .containsExactlyInAnyOrder( - tuple(member1.getId(), member1.getName()), - tuple(member2.getId(), member2.getName()), - tuple(member3.getId(), member3.getName()) + tuple(eventMember1.getId(), eventMember1.getName()), + tuple(eventMember2.getId(), eventMember2.getName()), + tuple(eventMember3.getId(), eventMember3.getName()) ); } @DisplayName("행사가 없으면 현재 참여 인원을 조회할 수 없다.") @Test void getCurrentMembersTest1() { - assertThatThrownBy(() -> memberService.getCurrentMembers("token")) + assertThatThrownBy(() -> eventMemberService.getCurrentMembers("token")) .isInstanceOf(HaengdongException.class); } } diff --git a/server/src/test/java/server/haengdong/application/EventImageFacadeServiceTest.java b/server/src/test/java/haengdong/application/EventImageFacadeServiceTest.java similarity index 92% rename from server/src/test/java/server/haengdong/application/EventImageFacadeServiceTest.java rename to server/src/test/java/haengdong/application/EventImageFacadeServiceTest.java index 7cfee215d..b82561b72 100644 --- a/server/src/test/java/server/haengdong/application/EventImageFacadeServiceTest.java +++ b/server/src/test/java/haengdong/application/EventImageFacadeServiceTest.java @@ -1,4 +1,4 @@ -package server.haengdong.application; +package haengdong.application; import static org.assertj.core.api.Assertions.assertThat; import static org.assertj.core.api.Assertions.assertThatThrownBy; @@ -19,13 +19,16 @@ import org.springframework.boot.test.mock.mockito.SpyBean; import org.springframework.mock.web.MockMultipartFile; import org.springframework.web.multipart.MultipartFile; -import server.haengdong.application.response.EventImageSaveAppResponse; -import server.haengdong.application.response.ImageInfo; -import server.haengdong.domain.event.Event; -import server.haengdong.domain.event.EventImageRepository; -import server.haengdong.domain.event.EventRepository; -import server.haengdong.exception.HaengdongException; -import server.haengdong.support.fixture.Fixture; +import haengdong.event.application.EventImageFacadeService; +import haengdong.event.application.EventService; +import haengdong.event.application.ImageService; +import haengdong.event.application.response.EventImageSaveAppResponse; +import haengdong.event.application.response.ImageInfo; +import haengdong.event.domain.event.Event; +import haengdong.event.domain.event.image.EventImageRepository; +import haengdong.event.domain.event.EventRepository; +import haengdong.common.exception.HaengdongException; +import haengdong.support.fixture.Fixture; class EventImageFacadeServiceTest extends ServiceTestSupport { diff --git a/server/src/test/java/haengdong/application/EventServiceTest.java b/server/src/test/java/haengdong/application/EventServiceTest.java new file mode 100644 index 000000000..c59760e7d --- /dev/null +++ b/server/src/test/java/haengdong/application/EventServiceTest.java @@ -0,0 +1,193 @@ +package haengdong.application; + + +import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.assertThatThrownBy; +import static org.assertj.core.api.AssertionsForClassTypes.tuple; +import static org.junit.jupiter.api.Assertions.assertAll; +import static org.mockito.BDDMockito.given; + +import haengdong.common.exception.HaengdongException; +import haengdong.event.application.EventService; +import haengdong.event.application.request.EventGuestAppRequest; +import haengdong.event.application.request.EventUpdateAppRequest; +import haengdong.event.application.response.EventAppResponse; +import haengdong.event.application.response.EventDetailAppResponse; +import haengdong.event.application.response.EventImageAppResponse; +import haengdong.event.application.response.MemberBillReportAppResponse; +import haengdong.event.domain.RandomValueProvider; +import haengdong.event.domain.bill.Bill; +import haengdong.event.domain.bill.BillRepository; +import haengdong.event.domain.event.Event; +import haengdong.event.domain.event.EventRepository; +import haengdong.event.domain.event.image.EventImage; +import haengdong.event.domain.event.image.EventImageRepository; +import haengdong.event.domain.event.member.EventMember; +import haengdong.event.domain.event.member.EventMemberRepository; +import haengdong.support.fixture.Fixture; +import java.util.List; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.mock.mockito.MockBean; + +class EventServiceTest extends ServiceTestSupport { + + @Autowired + private EventService eventService; + + @Autowired + private EventRepository eventRepository; + + @Autowired + private BillRepository billRepository; + + @Autowired + private EventMemberRepository eventMemberRepository; + + @Autowired + private EventImageRepository eventImageRepository; + + @MockBean + private RandomValueProvider randomValueProvider; + + @DisplayName("행사를 생성한다") + @Test + void saveEventGuestTest() { + EventGuestAppRequest request = new EventGuestAppRequest("test", "nickname", "1234"); + given(randomValueProvider.createRandomValue()).willReturn("TOKEN"); + + EventAppResponse response = eventService.saveEventGuest(request); + + assertThat(response.token()).isEqualTo("TOKEN"); + } + + @DisplayName("토큰으로 행사를 조회한다.") + @Test + void findEventTest() { + EventGuestAppRequest request = new EventGuestAppRequest("test", "nickname", "1234"); + given(randomValueProvider.createRandomValue()).willReturn("TOKEN"); + EventAppResponse response = eventService.saveEventGuest(request); + + EventDetailAppResponse eventDetailAppResponse = eventService.findEvent("TOKEN"); + + assertAll( + () -> assertThat(eventDetailAppResponse.eventName()).isEqualTo("test"), + () -> assertThat(eventDetailAppResponse.createdByGuest()).isEqualTo(true) + ); + } + + @DisplayName("행사 정보를 수정한다.") + @Test + void updateEventNameTest() { + Event event = new Event("행동대장 비대위", 1L, "token"); + eventRepository.save(event); + + EventUpdateAppRequest eventUpdateAppRequest = new EventUpdateAppRequest("새로운 행사 이름"); + eventService.updateEventName(event.getToken(), eventUpdateAppRequest); + + Event updateEvent = eventRepository.findByToken(event.getToken()).get(); + assertThat(updateEvent.getName()).isEqualTo("새로운 행사 이름"); + } + + @DisplayName("참여자별 정산 현황을 조회한다.") + @Test + void getMemberBillReports() { + Event event = Fixture.EVENT1; + Event savedEvent = eventRepository.save(event); + List eventMembers = List.of( + new EventMember(savedEvent, "소하"), + new EventMember(savedEvent, "감자"), + new EventMember(savedEvent, "쿠키"), + new EventMember(savedEvent, "고구마") + ); + eventMemberRepository.saveAll(eventMembers); + List bills = List.of( + Bill.create(savedEvent, "뽕족", 60_000L, eventMembers), + Bill.create(savedEvent, "인생네컷", 20_000L, eventMembers) + ); + billRepository.saveAll(bills); + + List responses = eventService.getMemberBillReports(event.getToken()); + + assertThat(responses) + .hasSize(4) + .extracting(MemberBillReportAppResponse::name, MemberBillReportAppResponse::price) + .containsExactlyInAnyOrder( + tuple("감자", 20_000L), + tuple("쿠키", 20_000L), + tuple("소하", 20_000L), + tuple("고구마", 20_000L) + ); + } + + @DisplayName("행사 이미지를 조회한다.") + @Test + void findAllImages() { + Event event = Fixture.EVENT1; + List eventImages = List.of( + new EventImage(event, "image1.jpg"), + new EventImage(event, "image2.jpg") + ); + eventRepository.save(event); + eventImageRepository.saveAll(eventImages); + + List responses = eventService.findImages(event.getToken()); + + assertThat(responses) + .hasSize(2) + .extracting(EventImageAppResponse::name) + .containsExactlyInAnyOrder( + "image1.jpg", + "image2.jpg" + ); + } + + @DisplayName("행사 이미지를 저장한다.") + @Test + void saveImages() { + Event event = Fixture.EVENT1; + eventRepository.save(event); + List imageNames = List.of("image1.jpg", "image2.jpg"); + given(randomValueProvider.createRandomValue()).willReturn("1234"); + + eventService.saveImages(event.getToken(), imageNames); + + List savedEventImages = eventImageRepository.findAllByEvent(event); + assertThat(savedEventImages) + .hasSize(2) + .extracting(EventImage::getName) + .containsExactlyInAnyOrder( + "1234image1.jpg", + "1234image2.jpg" + ); + } + + @DisplayName("행사 이미지를 삭제한다.") + @Test + void deleteImage() { + Event event = Fixture.EVENT1; + eventRepository.save(event); + EventImage eventImage = new EventImage(event, "image1.jpg"); + eventImageRepository.save(eventImage); + + eventService.deleteImage(event.getToken(), eventImage.getId()); + + assertThat(eventImageRepository.findById(eventImage.getId())) + .isEmpty(); + } + + @DisplayName("행사 1개당 이미지는 10개까지 업로드 가능하다.") + @Test + void validateImageCount() { + Event event = Fixture.EVENT1; + eventRepository.save(event); + List imageNames = List.of("image1.jpg", "image2.jpg"); + String token = event.getToken(); + eventService.saveImages(token, imageNames); + + assertThatThrownBy( + () -> eventService.saveImages(token, List.of("1", "2", "3", "4", "5", "6", "7", "8", "9"))) + .isInstanceOf(HaengdongException.class); + } +} diff --git a/server/src/test/java/server/haengdong/application/ImageServiceTest.java b/server/src/test/java/haengdong/application/ImageServiceTest.java similarity index 96% rename from server/src/test/java/server/haengdong/application/ImageServiceTest.java rename to server/src/test/java/haengdong/application/ImageServiceTest.java index f155ba579..bbcd5e642 100644 --- a/server/src/test/java/server/haengdong/application/ImageServiceTest.java +++ b/server/src/test/java/haengdong/application/ImageServiceTest.java @@ -1,4 +1,4 @@ -package server.haengdong.application; +package haengdong.application; import static org.assertj.core.api.Assertions.assertThatThrownBy; import static org.mockito.ArgumentMatchers.any; @@ -14,6 +14,7 @@ import org.springframework.boot.test.mock.mockito.MockBean; import org.springframework.mock.web.MockMultipartFile; import org.springframework.web.multipart.MultipartFile; +import haengdong.event.application.ImageService; import software.amazon.awssdk.core.sync.RequestBody; import software.amazon.awssdk.services.s3.S3Client; import software.amazon.awssdk.services.s3.model.DeleteObjectRequest; diff --git a/server/src/test/java/server/haengdong/application/ServiceTestSupport.java b/server/src/test/java/haengdong/application/ServiceTestSupport.java similarity index 75% rename from server/src/test/java/server/haengdong/application/ServiceTestSupport.java rename to server/src/test/java/haengdong/application/ServiceTestSupport.java index 008ba1035..451391731 100644 --- a/server/src/test/java/server/haengdong/application/ServiceTestSupport.java +++ b/server/src/test/java/haengdong/application/ServiceTestSupport.java @@ -1,9 +1,9 @@ -package server.haengdong.application; +package haengdong.application; import org.junit.jupiter.api.extension.ExtendWith; import org.springframework.boot.test.context.SpringBootTest; import org.springframework.boot.test.context.SpringBootTest.WebEnvironment; -import server.haengdong.support.extension.DatabaseCleanerExtension; +import haengdong.support.extension.DatabaseCleanerExtension; @ExtendWith(DatabaseCleanerExtension.class) @SpringBootTest(webEnvironment = WebEnvironment.NONE) diff --git a/server/src/test/java/server/haengdong/docs/AdminBillControllerDocsTest.java b/server/src/test/java/haengdong/docs/AdminBillControllerDocsTest.java similarity index 89% rename from server/src/test/java/server/haengdong/docs/AdminBillControllerDocsTest.java rename to server/src/test/java/haengdong/docs/AdminBillControllerDocsTest.java index 1c275801e..afdc82294 100644 --- a/server/src/test/java/server/haengdong/docs/AdminBillControllerDocsTest.java +++ b/server/src/test/java/haengdong/docs/AdminBillControllerDocsTest.java @@ -1,4 +1,4 @@ -package server.haengdong.docs; +package haengdong.docs; import static org.mockito.Mockito.mock; import static org.springframework.restdocs.cookies.CookieDocumentation.cookieWithName; @@ -16,20 +16,20 @@ import static org.springframework.restdocs.request.RequestDocumentation.pathParameters; import static org.springframework.test.web.servlet.result.MockMvcResultHandlers.print; import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; -import static server.haengdong.support.fixture.Fixture.EVENT_COOKIE; +import static haengdong.support.fixture.Fixture.EVENT_COOKIE; import java.util.List; import org.junit.jupiter.api.DisplayName; import org.junit.jupiter.api.Test; import org.springframework.http.MediaType; import org.springframework.restdocs.payload.JsonFieldType; -import server.haengdong.application.BillService; -import server.haengdong.presentation.admin.AdminBillController; -import server.haengdong.presentation.request.BillDetailUpdateRequest; -import server.haengdong.presentation.request.BillDetailsUpdateRequest; -import server.haengdong.presentation.request.BillSaveRequest; -import server.haengdong.presentation.request.BillUpdateRequest; -import server.haengdong.support.fixture.Fixture; +import haengdong.event.application.BillService; +import haengdong.event.presentation.admin.AdminBillController; +import haengdong.event.presentation.request.BillDetailUpdateRequest; +import haengdong.event.presentation.request.BillDetailsUpdateRequest; +import haengdong.event.presentation.request.BillSaveRequest; +import haengdong.event.presentation.request.BillUpdateRequest; +import haengdong.support.fixture.Fixture; class AdminBillControllerDocsTest extends RestDocsSupport { @@ -62,7 +62,7 @@ void saveAllBill() throws Exception { parameterWithName("eventId").description("행사 ID") ), requestCookies( - cookieWithName("eventToken").description("행사 관리자 토큰") + cookieWithName("accessToken").description("행사 관리자 토큰") ), requestFields( fieldWithPath("title").description("생성할 지출 제목"), @@ -94,7 +94,7 @@ void updateBill() throws Exception { parameterWithName("billId").description("지출 ID") ), requestCookies( - cookieWithName("eventToken").description("행사 관리자 토큰") + cookieWithName("accessToken").description("행사 관리자 토큰") ), requestFields( fieldWithPath("title").description("수정할 지출 제목"), @@ -130,7 +130,7 @@ void updateBillDetailsTest() throws Exception { parameterWithName("billId").description("지출 ID") ), requestCookies( - cookieWithName("eventToken").description("행사 관리자 토큰") + cookieWithName("accessToken").description("행사 관리자 토큰") ), requestFields( fieldWithPath("billDetails").type(JsonFieldType.ARRAY) @@ -164,7 +164,7 @@ void deleteBill() throws Exception { parameterWithName("billId").description("지출 ID") ), requestCookies( - cookieWithName("eventToken").description("행사 관리자 토큰") + cookieWithName("accessToken").description("행사 관리자 토큰") ) )); } diff --git a/server/src/test/java/server/haengdong/docs/AdminEventControllerDocsTest.java b/server/src/test/java/haengdong/docs/AdminEventControllerDocsTest.java similarity index 85% rename from server/src/test/java/server/haengdong/docs/AdminEventControllerDocsTest.java rename to server/src/test/java/haengdong/docs/AdminEventControllerDocsTest.java index b5bb5cda8..583475a16 100644 --- a/server/src/test/java/server/haengdong/docs/AdminEventControllerDocsTest.java +++ b/server/src/test/java/haengdong/docs/AdminEventControllerDocsTest.java @@ -1,13 +1,14 @@ -package server.haengdong.docs; +package haengdong.docs; +import static haengdong.support.fixture.Fixture.EVENT_COOKIE; import static org.mockito.Mockito.mock; import static org.springframework.restdocs.cookies.CookieDocumentation.cookieWithName; import static org.springframework.restdocs.cookies.CookieDocumentation.requestCookies; import static org.springframework.restdocs.mockmvc.MockMvcRestDocumentation.document; +import static org.springframework.restdocs.mockmvc.RestDocumentationRequestBuilders.delete; import static org.springframework.restdocs.mockmvc.RestDocumentationRequestBuilders.multipart; import static org.springframework.restdocs.mockmvc.RestDocumentationRequestBuilders.patch; import static org.springframework.restdocs.mockmvc.RestDocumentationRequestBuilders.post; -import static org.springframework.restdocs.mockmvc.RestDocumentationRequestBuilders.delete; import static org.springframework.restdocs.operation.preprocess.Preprocessors.preprocessRequest; import static org.springframework.restdocs.operation.preprocess.Preprocessors.preprocessResponse; import static org.springframework.restdocs.operation.preprocess.Preprocessors.prettyPrint; @@ -19,17 +20,16 @@ import static org.springframework.restdocs.request.RequestDocumentation.requestParts; import static org.springframework.test.web.servlet.result.MockMvcResultHandlers.print; import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; -import static server.haengdong.support.fixture.Fixture.EVENT_COOKIE; +import haengdong.event.application.EventImageFacadeService; +import haengdong.event.application.EventService; +import haengdong.event.presentation.admin.AdminEventController; +import haengdong.event.presentation.request.EventUpdateRequest; import org.junit.jupiter.api.DisplayName; import org.junit.jupiter.api.Test; import org.springframework.http.MediaType; import org.springframework.mock.web.MockMultipartFile; import org.springframework.restdocs.payload.JsonFieldType; -import server.haengdong.application.EventImageFacadeService; -import server.haengdong.application.EventService; -import server.haengdong.presentation.admin.AdminEventController; -import server.haengdong.presentation.request.EventUpdateRequest; class AdminEventControllerDocsTest extends RestDocsSupport { @@ -58,7 +58,7 @@ void authenticateTest() throws Exception { parameterWithName("eventId").description("행사 ID") ), requestCookies( - cookieWithName("eventToken").description("행사 관리자 토큰").optional() + cookieWithName("accessToken").description("행사 관리자 토큰").optional() ) ) ); @@ -68,7 +68,7 @@ void authenticateTest() throws Exception { @Test void updateEventTest() throws Exception { String token = "TOKEN"; - EventUpdateRequest eventUpdateRequest = new EventUpdateRequest("행동대장 비대위", "행대뱅크", "12345678"); + EventUpdateRequest eventUpdateRequest = new EventUpdateRequest("행동대장 비대위"); String requestBody = objectMapper.writeValueAsString(eventUpdateRequest); @@ -86,15 +86,11 @@ void updateEventTest() throws Exception { parameterWithName("eventId").description("행사 ID") ), requestCookies( - cookieWithName("eventToken").description("행사 관리자 토큰") + cookieWithName("accessToken").description("행사 관리자 토큰") ), requestFields( fieldWithPath("eventName").type(JsonFieldType.STRING) - .description("수정할 이벤트 이름").optional(), - fieldWithPath("bankName").type(JsonFieldType.STRING) - .description("은행 이름").optional(), - fieldWithPath("accountNumber").type(JsonFieldType.STRING) - .description("계좌 번호").optional() + .description("수정할 이벤트 이름").optional() ) ) ); @@ -122,7 +118,7 @@ void uploadImages() throws Exception { parameterWithName("eventId").description("행사 ID") ), requestCookies( - cookieWithName("eventToken").description("행사 관리자 토큰") + cookieWithName("accessToken").description("행사 관리자 토큰") ), requestParts( partWithName("images").description("행사 이미지") @@ -149,7 +145,7 @@ void deleteImage() throws Exception { parameterWithName("imageId").description("이미지 ID") ), requestCookies( - cookieWithName("eventToken").description("행사 관리자 토큰") + cookieWithName("accessToken").description("행사 관리자 토큰") ) ) ); diff --git a/server/src/test/java/server/haengdong/docs/AdminMemberControllerDocsTest.java b/server/src/test/java/haengdong/docs/AdminEventEventMemberControllerDocsTest.java similarity index 87% rename from server/src/test/java/server/haengdong/docs/AdminMemberControllerDocsTest.java rename to server/src/test/java/haengdong/docs/AdminEventEventMemberControllerDocsTest.java index 9d70673f9..3d4e7ee6d 100644 --- a/server/src/test/java/server/haengdong/docs/AdminMemberControllerDocsTest.java +++ b/server/src/test/java/haengdong/docs/AdminEventEventMemberControllerDocsTest.java @@ -1,4 +1,4 @@ -package server.haengdong.docs; +package haengdong.docs; import static org.hamcrest.Matchers.equalTo; import static org.mockito.BDDMockito.given; @@ -19,7 +19,7 @@ import static org.springframework.restdocs.request.RequestDocumentation.pathParameters; import static org.springframework.test.web.servlet.result.MockMvcResultHandlers.print; import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; -import static server.haengdong.support.fixture.Fixture.EVENT_COOKIE; +import static haengdong.support.fixture.Fixture.EVENT_COOKIE; import java.util.List; import org.junit.jupiter.api.DisplayName; @@ -27,22 +27,22 @@ import org.springframework.http.MediaType; import org.springframework.restdocs.payload.JsonFieldType; import org.springframework.test.web.servlet.result.MockMvcResultMatchers; -import server.haengdong.application.MemberService; -import server.haengdong.application.response.MemberSaveAppResponse; -import server.haengdong.application.response.MembersSaveAppResponse; -import server.haengdong.presentation.admin.AdminMemberController; -import server.haengdong.presentation.request.MemberSaveRequest; -import server.haengdong.presentation.request.MemberUpdateRequest; -import server.haengdong.presentation.request.MembersSaveRequest; -import server.haengdong.presentation.request.MembersUpdateRequest; +import haengdong.event.application.EventMemberService; +import haengdong.event.application.response.MemberSaveAppResponse; +import haengdong.event.application.response.MembersSaveAppResponse; +import haengdong.event.presentation.admin.AdminMemberController; +import haengdong.event.presentation.request.MemberSaveRequest; +import haengdong.event.presentation.request.MemberUpdateRequest; +import haengdong.event.presentation.request.MembersSaveRequest; +import haengdong.event.presentation.request.MembersUpdateRequest; -class AdminMemberControllerDocsTest extends RestDocsSupport { +class AdminEventEventMemberControllerDocsTest extends RestDocsSupport { - private final MemberService memberService = mock(MemberService.class); + private final EventMemberService eventMemberService = mock(EventMemberService.class); @Override protected Object initController() { - return new AdminMemberController(memberService); + return new AdminMemberController(eventMemberService); } @DisplayName("행사 참여자를 추가한다.") @@ -62,7 +62,7 @@ void saveMemberTest() throws Exception { new MemberSaveAppResponse(2L, "소하") ) ); - given(memberService.saveMembers(eventToken, membersSaveRequest.toAppRequest())) + given(eventMemberService.saveMembers(eventToken, membersSaveRequest.toAppRequest())) .willReturn(appResponse); mockMvc.perform(post("/api/admin/events/{eventId}/members", "망쵸토큰") @@ -83,7 +83,7 @@ void saveMemberTest() throws Exception { parameterWithName("eventId").description("행사 ID") ), requestCookies( - cookieWithName("eventToken").description("토큰 토큰") + cookieWithName("accessToken").description("토큰 토큰") ), requestFields( fieldWithPath("members").type(JsonFieldType.ARRAY) @@ -122,7 +122,7 @@ void deleteMember() throws Exception { parameterWithName("memberId").description("삭제할 참여자 ID") ), requestCookies( - cookieWithName("eventToken").description("행사 토큰") + cookieWithName("accessToken").description("행사 토큰") ) ) ); @@ -155,7 +155,7 @@ void updateMembers() throws Exception { parameterWithName("eventId").description("행사 ID") ), requestCookies( - cookieWithName("eventToken").description("행사 토큰") + cookieWithName("accessToken").description("행사 토큰") ), requestFields( fieldWithPath("members").type(JsonFieldType.ARRAY) diff --git a/server/src/test/java/server/haengdong/docs/BillControllerDocsTest.java b/server/src/test/java/haengdong/docs/BillControllerDocsTest.java similarity index 89% rename from server/src/test/java/server/haengdong/docs/BillControllerDocsTest.java rename to server/src/test/java/haengdong/docs/BillControllerDocsTest.java index 0716a2123..cfbbf6ed5 100644 --- a/server/src/test/java/server/haengdong/docs/BillControllerDocsTest.java +++ b/server/src/test/java/haengdong/docs/BillControllerDocsTest.java @@ -1,4 +1,4 @@ -package server.haengdong.docs; +package haengdong.docs; import static org.mockito.ArgumentMatchers.anyLong; import static org.mockito.ArgumentMatchers.anyString; @@ -20,16 +20,16 @@ import java.util.List; import org.junit.jupiter.api.DisplayName; import org.junit.jupiter.api.Test; -import server.haengdong.application.BillService; -import server.haengdong.application.response.BillAppResponse; -import server.haengdong.application.response.BillDetailAppResponse; -import server.haengdong.application.response.BillDetailsAppResponse; -import server.haengdong.application.response.MemberAppResponse; -import server.haengdong.application.response.StepAppResponse; -import server.haengdong.domain.bill.Bill; -import server.haengdong.domain.member.Member; -import server.haengdong.presentation.BillController; -import server.haengdong.support.fixture.Fixture; +import haengdong.event.application.BillService; +import haengdong.event.application.response.BillAppResponse; +import haengdong.event.application.response.BillDetailAppResponse; +import haengdong.event.application.response.BillDetailsAppResponse; +import haengdong.event.application.response.MemberAppResponse; +import haengdong.event.application.response.StepAppResponse; +import haengdong.event.domain.bill.Bill; +import haengdong.event.domain.event.member.EventMember; +import haengdong.event.presentation.BillController; +import haengdong.support.fixture.Fixture; class BillControllerDocsTest extends RestDocsSupport { @@ -46,8 +46,8 @@ void findBills() throws Exception { Bill bill = Fixture.BILL1; List bills = List.of(BillAppResponse.of(bill)); - Member member = Fixture.MEMBER1; - List members = List.of(MemberAppResponse.of(member)); + EventMember eventMember = Fixture.EVENT_MEMBER_1; + List members = List.of(MemberAppResponse.of(eventMember)); StepAppResponse stepAppResponse = new StepAppResponse(bills, members); given(billService.findSteps(anyString())).willReturn(List.of(stepAppResponse)); @@ -62,8 +62,8 @@ void findBills() throws Exception { .andExpect(jsonPath("$.steps[0].bills[0].price").value(bill.getPrice())) .andExpect(jsonPath("$.steps[0].bills[0].isFixed").value(bill.isFixed())) .andExpect(jsonPath("$.steps[0].members").isArray()) - .andExpect(jsonPath("$.steps[0].members[0].id").value(member.getId())) - .andExpect(jsonPath("$.steps[0].members[0].name").value(member.getName())) + .andExpect(jsonPath("$.steps[0].members[0].id").value(eventMember.getId())) + .andExpect(jsonPath("$.steps[0].members[0].name").value(eventMember.getName())) .andDo(document("findBills", preprocessRequest(prettyPrint()), preprocessResponse(prettyPrint()), diff --git a/server/src/test/java/server/haengdong/docs/EventControllerDocsTest.java b/server/src/test/java/haengdong/docs/EventControllerDocsTest.java similarity index 71% rename from server/src/test/java/server/haengdong/docs/EventControllerDocsTest.java rename to server/src/test/java/haengdong/docs/EventControllerDocsTest.java index 0918721fd..dce75cf65 100644 --- a/server/src/test/java/server/haengdong/docs/EventControllerDocsTest.java +++ b/server/src/test/java/haengdong/docs/EventControllerDocsTest.java @@ -1,10 +1,11 @@ -package server.haengdong.docs; +package haengdong.docs; import static org.hamcrest.Matchers.equalTo; import static org.mockito.ArgumentMatchers.any; import static org.mockito.BDDMockito.given; import static org.mockito.Mockito.mock; import static org.springframework.restdocs.cookies.CookieDocumentation.cookieWithName; +import static org.springframework.restdocs.cookies.CookieDocumentation.requestCookies; import static org.springframework.restdocs.cookies.CookieDocumentation.responseCookies; import static org.springframework.restdocs.mockmvc.MockMvcRestDocumentation.document; import static org.springframework.restdocs.mockmvc.RestDocumentationRequestBuilders.get; @@ -22,6 +23,21 @@ import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.jsonPath; import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; +import haengdong.common.auth.application.AuthService; +import haengdong.common.properties.CookieProperties; +import haengdong.event.application.EventImageFacadeService; +import haengdong.event.application.EventService; +import haengdong.event.application.request.EventAppRequest; +import haengdong.event.application.request.EventGuestAppRequest; +import haengdong.event.application.response.EventAppResponse; +import haengdong.event.application.response.EventDetailAppResponse; +import haengdong.event.application.response.EventImageUrlAppResponse; +import haengdong.event.application.response.MemberBillReportAppResponse; +import haengdong.event.presentation.EventController; +import haengdong.event.presentation.request.EventGuestSaveRequest; +import haengdong.event.presentation.request.EventLoginRequest; +import haengdong.event.presentation.request.EventSaveRequest; +import haengdong.support.fixture.Fixture; import java.time.Duration; import java.util.List; import org.junit.jupiter.api.DisplayName; @@ -29,17 +45,6 @@ import org.springframework.http.MediaType; import org.springframework.restdocs.payload.JsonFieldType; import org.springframework.test.web.servlet.result.MockMvcResultMatchers; -import server.haengdong.application.AuthService; -import server.haengdong.application.EventService; -import server.haengdong.application.request.EventAppRequest; -import server.haengdong.application.response.EventAppResponse; -import server.haengdong.application.response.EventDetailAppResponse; -import server.haengdong.application.response.EventImageAppResponse; -import server.haengdong.application.response.MemberBillReportAppResponse; -import server.haengdong.infrastructure.auth.CookieProperties; -import server.haengdong.presentation.EventController; -import server.haengdong.presentation.request.EventLoginRequest; -import server.haengdong.presentation.request.EventSaveRequest; class EventControllerDocsTest extends RestDocsSupport { @@ -48,17 +53,18 @@ class EventControllerDocsTest extends RestDocsSupport { private final CookieProperties cookieProperties = new CookieProperties( true, true, "domain", "path", "none", Duration.ofDays(7) ); + private final EventImageFacadeService eventImageFacadeService = mock(EventImageFacadeService.class); @Override protected Object initController() { - return new EventController(eventService, authService, cookieProperties); + return new EventController(eventService, authService, cookieProperties, eventImageFacadeService); } @DisplayName("토큰으로 행사를 조회한다.") @Test void findEventTest() throws Exception { String eventId = "망쵸토큰"; - EventDetailAppResponse eventDetailAppResponse = new EventDetailAppResponse("행동대장 회식", "토스뱅크", "12312455"); + EventDetailAppResponse eventDetailAppResponse = new EventDetailAppResponse("행동대장 회식", "토스뱅크", "12312455", true); given(eventService.findEvent(eventId)).willReturn(eventDetailAppResponse); mockMvc.perform(get("/api/events/{eventId}", eventId)) @@ -75,7 +81,8 @@ void findEventTest() throws Exception { responseFields( fieldWithPath("eventName").type(JsonFieldType.STRING).description("행사 이름"), fieldWithPath("bankName").type(JsonFieldType.STRING).description("토스뱅크"), - fieldWithPath("accountNumber").type(JsonFieldType.STRING).description("12312455") + fieldWithPath("accountNumber").type(JsonFieldType.STRING).description("12312455"), + fieldWithPath("createdByGuest").type(JsonFieldType.BOOLEAN).description(true) ) ) ); @@ -124,38 +131,39 @@ void getMemberBillReports() throws Exception { ); } - @DisplayName("이벤트를 생성한다.") + @DisplayName("비회원으로 이벤트를 생성한다.") @Test - void saveEvent() throws Exception { - EventSaveRequest eventSaveRequest = new EventSaveRequest("토다리", "0987"); + void saveEventGuest() throws Exception { + EventGuestSaveRequest eventSaveRequest = new EventGuestSaveRequest("토다리", "nickname", "1234"); String requestBody = objectMapper.writeValueAsString(eventSaveRequest); String eventId = "쿠키 토큰"; - EventAppResponse eventAppResponse = new EventAppResponse(eventId); - given(eventService.saveEvent(any(EventAppRequest.class))).willReturn(eventAppResponse); - given(authService.createToken(eventId)).willReturn("jwtToken"); - given(authService.getTokenName()).willReturn("eventToken"); + EventAppResponse eventAppResponse = new EventAppResponse(eventId, 1L); + given(eventService.saveEventGuest(any(EventGuestAppRequest.class))).willReturn(eventAppResponse); + given(authService.createGuestToken(1L)).willReturn("jwtToken"); + given(authService.getTokenName()).willReturn("accessToken"); - mockMvc.perform(post("/api/events") + mockMvc.perform(post("/api/events/guest") .contentType(MediaType.APPLICATION_JSON) .content(requestBody)) .andDo(print()) .andExpect(status().isOk()) - .andExpect(cookie().value("eventToken", "jwtToken")) + .andExpect(cookie().value("accessToken", "jwtToken")) .andExpect(jsonPath("$.eventId").value("쿠키 토큰")) .andDo( - document("createEvent", + document("createGuestEvent", preprocessRequest(prettyPrint()), preprocessResponse(prettyPrint()), requestFields( fieldWithPath("eventName").type(JsonFieldType.STRING).description("행사 이름"), - fieldWithPath("password").type(JsonFieldType.STRING).description("행사 비밀 번호") + fieldWithPath("nickname").type(JsonFieldType.STRING).description("비회원 닉네임"), + fieldWithPath("password").type(JsonFieldType.STRING).description("비회원 비밀번호") ), responseFields( fieldWithPath("eventId").type(JsonFieldType.STRING) .description("행사 ID") ), responseCookies( - cookieWithName("eventToken").description("행사 관리자용 토큰") + cookieWithName("accessToken").description("행사 관리자용 토큰") ) ) ); @@ -167,14 +175,15 @@ void loginEvent() throws Exception { String token = "TOKEN"; EventLoginRequest eventLoginRequest = new EventLoginRequest("1234"); String requestBody = objectMapper.writeValueAsString(eventLoginRequest); - given(authService.createToken(token)).willReturn("jwtToken"); - given(authService.getTokenName()).willReturn("eventToken"); + given(authService.createGuestToken(1L)).willReturn("jwtToken"); + given(authService.getTokenName()).willReturn("accessToken"); + given(eventService.findByGuestPassword(any())).willReturn(new EventAppResponse("TOKEN", 1L)); mockMvc.perform(post("/api/events/{eventId}/login", token) .contentType(MediaType.APPLICATION_JSON) .content(requestBody)) .andDo(print()) - .andExpect(cookie().value("eventToken", "jwtToken")) + .andExpect(cookie().value("accessToken", "jwtToken")) .andExpect(status().isOk()) .andDo( document("eventLogin", @@ -188,23 +197,55 @@ void loginEvent() throws Exception { .description("행사 비밀 번호") ), responseCookies( - cookieWithName("eventToken").description("행사 관리자용 토큰") + cookieWithName("accessToken").description("행사 관리자용 토큰") ) ) ); } + @DisplayName("이벤트를 생성한다.") + @Test + void saveEvent() throws Exception { + EventSaveRequest eventSaveRequest = new EventSaveRequest("토다리"); + String requestBody = objectMapper.writeValueAsString(eventSaveRequest); + String eventId = "쿠키 토큰"; + EventAppResponse eventAppResponse = new EventAppResponse(eventId, 1L); + given(eventService.saveEvent(any(EventAppRequest.class))).willReturn(eventAppResponse); + + mockMvc.perform(post("/api/events") + .contentType(MediaType.APPLICATION_JSON) + .content(requestBody) + .cookie(Fixture.EVENT_COOKIE)) + .andDo(print()) + .andExpect(status().isOk()) + .andDo( + document("createEvent", + preprocessRequest(prettyPrint()), + preprocessResponse(prettyPrint()), + requestFields( + fieldWithPath("eventName").type(JsonFieldType.STRING).description("행사 이름") + ), + requestCookies( + cookieWithName("accessToken").description("행사 관리자 토큰") + ), + responseFields( + fieldWithPath("eventId").type(JsonFieldType.STRING) + .description("행사 ID") + ) + ) + ); + } @DisplayName("행사 이미지를 조회한다.") @Test void findAllImages() throws Exception { String token = "TOKEN"; - List imageNameAppResponses = List.of( - new EventImageAppResponse(1L, "https://host.com/image1.jpg"), - new EventImageAppResponse(2L, "https://host.com/image2.jpg"), - new EventImageAppResponse(3L, "https://host.com/zeze.jpg") + List imageNameAppResponses = List.of( + new EventImageUrlAppResponse(1L, "https://host.com/image1.jpg"), + new EventImageUrlAppResponse(2L, "https://host.com/image2.jpg"), + new EventImageUrlAppResponse(3L, "https://host.com/zeze.jpg") ); - given(eventService.findImages(token)).willReturn(imageNameAppResponses); + given(eventImageFacadeService.findImages(token)).willReturn(imageNameAppResponses); mockMvc.perform(get("/api/events/{eventId}/images", token)) .andDo(print()) diff --git a/server/src/test/java/server/haengdong/docs/MemberControllerDocsTest.java b/server/src/test/java/haengdong/docs/EventEventMemberControllerDocsTest.java similarity index 89% rename from server/src/test/java/server/haengdong/docs/MemberControllerDocsTest.java rename to server/src/test/java/haengdong/docs/EventEventMemberControllerDocsTest.java index 2997ad4ee..8e7ab72c9 100644 --- a/server/src/test/java/server/haengdong/docs/MemberControllerDocsTest.java +++ b/server/src/test/java/haengdong/docs/EventEventMemberControllerDocsTest.java @@ -1,4 +1,4 @@ -package server.haengdong.docs; +package haengdong.docs; import static org.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.anyString; @@ -21,19 +21,19 @@ import org.junit.jupiter.api.DisplayName; import org.junit.jupiter.api.Test; import org.springframework.restdocs.payload.JsonFieldType; -import server.haengdong.application.MemberService; -import server.haengdong.application.response.MemberAppResponse; -import server.haengdong.application.response.MemberDepositAppResponse; -import server.haengdong.application.response.MembersDepositAppResponse; -import server.haengdong.presentation.MemberController; +import haengdong.event.application.EventMemberService; +import haengdong.event.application.response.MemberAppResponse; +import haengdong.event.application.response.MemberDepositAppResponse; +import haengdong.event.application.response.MembersDepositAppResponse; +import haengdong.event.presentation.EventMemberController; -class MemberControllerDocsTest extends RestDocsSupport { +class EventEventMemberControllerDocsTest extends RestDocsSupport { - private final MemberService memberService = mock(MemberService.class); + private final EventMemberService eventMemberService = mock(EventMemberService.class); @Override protected Object initController() { - return new MemberController(memberService); + return new EventMemberController(eventMemberService); } @DisplayName("행사에 참여한 전체 인원을 조회한다.") @@ -46,7 +46,7 @@ void findAllMembersTest() throws Exception { ); MembersDepositAppResponse memberAppResponse = new MembersDepositAppResponse(members); - given(memberService.findAllMembers(anyString())).willReturn(memberAppResponse); + given(eventMemberService.findAllMembers(anyString())).willReturn(memberAppResponse); mockMvc.perform(get("/api/events/{eventId}/members", "TOKEN")) .andDo(print()) @@ -90,7 +90,7 @@ void getCurrentMembers() throws Exception { new MemberAppResponse(2L, "백호") ); - given(memberService.getCurrentMembers(any())).willReturn(members); + given(eventMemberService.getCurrentMembers(any())).willReturn(members); mockMvc.perform(get("/api/events/{eventId}/members/current", "TOKEN")) .andExpect(status().isOk()) diff --git a/server/src/test/java/server/haengdong/docs/RestDocsSupport.java b/server/src/test/java/haengdong/docs/RestDocsSupport.java similarity index 96% rename from server/src/test/java/server/haengdong/docs/RestDocsSupport.java rename to server/src/test/java/haengdong/docs/RestDocsSupport.java index 3e6901ba8..b882d5f31 100644 --- a/server/src/test/java/server/haengdong/docs/RestDocsSupport.java +++ b/server/src/test/java/haengdong/docs/RestDocsSupport.java @@ -1,4 +1,4 @@ -package server.haengdong.docs; +package haengdong.docs; import static org.springframework.restdocs.mockmvc.MockMvcRestDocumentation.documentationConfiguration; diff --git a/server/src/test/java/server/haengdong/domain/bill/BillTest.java b/server/src/test/java/haengdong/domain/bill/BillTest.java similarity index 54% rename from server/src/test/java/server/haengdong/domain/bill/BillTest.java rename to server/src/test/java/haengdong/domain/bill/BillTest.java index d1c2e3d8c..7ddac243b 100644 --- a/server/src/test/java/server/haengdong/domain/bill/BillTest.java +++ b/server/src/test/java/haengdong/domain/bill/BillTest.java @@ -1,17 +1,18 @@ -package server.haengdong.domain.bill; +package haengdong.domain.bill; import static org.assertj.core.api.Assertions.assertThat; import static org.assertj.core.api.Assertions.assertThatThrownBy; import static org.junit.jupiter.api.Assertions.assertAll; -import static server.haengdong.support.fixture.Fixture.EVENT1; +import static haengdong.support.fixture.Fixture.EVENT1; import java.util.List; import org.junit.jupiter.api.DisplayName; import org.junit.jupiter.api.Test; import org.junit.jupiter.params.ParameterizedTest; import org.junit.jupiter.params.provider.ValueSource; -import server.haengdong.domain.member.Member; -import server.haengdong.exception.HaengdongException; +import haengdong.event.domain.bill.Bill; +import haengdong.event.domain.event.member.EventMember; +import haengdong.common.exception.HaengdongException; class BillTest { @@ -54,45 +55,9 @@ void createBill() { @DisplayName("지출에 멤버별 고정 금액이 설정되어 있는지 확인한다.") @Test void isFixed1() { - List members = List.of(new Member(EVENT1, "감자"), new Member(EVENT1, "고구마")); - Bill fixedBill = Bill.create(EVENT1, "인생네컷", 2_000L, members); + List eventMembers = List.of(new EventMember(EVENT1, "감자"), new EventMember(EVENT1, "고구마")); + Bill fixedBill = Bill.create(EVENT1, "인생네컷", 2_000L, eventMembers); assertThat(fixedBill.isFixed()).isEqualTo(false); } - - @DisplayName("같은 멤버 목록을 가지고 있는지 비교한다.") - @Test - void isSameMember1() { - Member member1 = new Member(1L, EVENT1, "감자", false); - Member member2 = new Member(2L, EVENT1, "고구마", false); - Member member3 = new Member(3L, EVENT1, "당근", false); - - List members1 = List.of(member1, member2, member3); - List members2 = List.of(member2, member3, member1); - - Bill bill1 = Bill.create(EVENT1, "뽕족", 20_000L, members1); - Bill bill2 = Bill.create(EVENT1, "인생네컷", 30_000L, members2); - - boolean isSameMembers = bill1.isSameMembers(bill2); - - assertThat(isSameMembers).isTrue(); - } - - @DisplayName("같은 멤버 목록을 가지고 있는지 비교한다.") - @Test - void isSameMember2() { - Member member1 = new Member(1L, EVENT1, "감자", false); - Member member2 = new Member(2L, EVENT1, "고구마", false); - Member member3 = new Member(3L, EVENT1, "당근", false); - - List members1 = List.of(member1, member2, member3); - List members2 = List.of(member2, member1); - - Bill bill1 = Bill.create(EVENT1, "뽕족", 20_000L, members1); - Bill bill2 = Bill.create(EVENT1, "인생네컷", 30_000L, members2); - - boolean isSameMembers = bill1.isSameMembers(bill2); - - assertThat(isSameMembers).isFalse(); - } } diff --git a/server/src/test/java/haengdong/domain/event/EventTest.java b/server/src/test/java/haengdong/domain/event/EventTest.java new file mode 100644 index 000000000..c0d607dad --- /dev/null +++ b/server/src/test/java/haengdong/domain/event/EventTest.java @@ -0,0 +1,50 @@ +package haengdong.domain.event; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.assertThatCode; + +import haengdong.common.exception.HaengdongException; +import haengdong.event.domain.event.Event; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.ValueSource; + +class EventTest { + + @DisplayName("공백 문자가 연속되지 않고, 이름이 2자 이상 20자 이하인 행사를 생성하면 예외가 발생하지 않는다.") + @ParameterizedTest + @ValueSource(strings = {"12", "12345678901234567890", "공 백", " 공백", "공백 ", " 공 백 "}) + void createSuccessTest(String eventName) { + assertThatCode(() -> new Event(eventName, 1L, "TEST_TOKEN")) + .doesNotThrowAnyException(); + } + + @DisplayName("공백 문자가 연속되면 예외가 발생한다.") + @ParameterizedTest + @ValueSource(strings = {" 공백", "공백 ", "공백 연속", "공 백"}) + void createFailTest1(String eventName) { + assertThatCode(() -> new Event(eventName, 1L, "TEST_TOKEN")) + .isInstanceOf(HaengdongException.class) + .hasMessage("행사 이름에는 공백 문자가 연속될 수 없습니다."); + } + + @DisplayName("이름이 1자 미만이거나 20자 초과인 경우 예외가 발생한다.") + @ParameterizedTest + @ValueSource(strings = {"", " ", "123456789012345678901"}) + void createFilTest2(String eventName) { + assertThatCode(() -> new Event(eventName, 1L, "TEST_TOKEN")) + .isInstanceOf(HaengdongException.class) + .hasMessage("행사 이름은 1자 이상 20자 이하만 입력 가능합니다."); + } + + @DisplayName("이름을 수정한다.") + @Test + void renameTest() { + Event event = new Event("이름", 1L, "TEST_TOKEN"); + + event.rename("새로운 이름"); + + assertThat(event.getName()).isEqualTo("새로운 이름"); + } +} diff --git a/server/src/test/java/server/haengdong/domain/event/PasswordTest.java b/server/src/test/java/haengdong/domain/event/PasswordTest.java similarity index 80% rename from server/src/test/java/server/haengdong/domain/event/PasswordTest.java rename to server/src/test/java/haengdong/domain/event/PasswordTest.java index c504d3aa2..acd518e86 100644 --- a/server/src/test/java/server/haengdong/domain/event/PasswordTest.java +++ b/server/src/test/java/haengdong/domain/event/PasswordTest.java @@ -1,11 +1,12 @@ -package server.haengdong.domain.event; +package haengdong.domain.event; import static org.assertj.core.api.Assertions.assertThatCode; import org.junit.jupiter.api.DisplayName; import org.junit.jupiter.params.ParameterizedTest; import org.junit.jupiter.params.provider.ValueSource; -import server.haengdong.exception.HaengdongException; +import haengdong.event.domain.event.Password; +import haengdong.common.exception.HaengdongException; class PasswordTest { diff --git a/server/src/test/java/haengdong/domain/eventmember/EventMemberBillReportTest.java b/server/src/test/java/haengdong/domain/eventmember/EventMemberBillReportTest.java new file mode 100644 index 000000000..7e79d334c --- /dev/null +++ b/server/src/test/java/haengdong/domain/eventmember/EventMemberBillReportTest.java @@ -0,0 +1,45 @@ +package haengdong.domain.eventmember; + +import static org.assertj.core.api.Assertions.assertThat; + +import java.util.List; +import java.util.Map; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; +import haengdong.event.domain.bill.Bill; +import haengdong.event.domain.event.Event; +import haengdong.event.domain.bill.MemberBillReport; +import haengdong.event.domain.event.member.EventMember; +import haengdong.support.fixture.Fixture; + +class EventMemberBillReportTest { + + @DisplayName("지출 목록으로 참가자 정산 리포트를 생성한다.") + @Test + void create() { + Event event = Fixture.EVENT1; + EventMember eventMember1 = new EventMember(1L, event, "소하", false); + EventMember eventMember2 = new EventMember(2L, event, "감자", false); + EventMember eventMember3 = new EventMember(3L, event, "쿠키", false); + EventMember eventMember4 = new EventMember(4L, event, "고구마", false); + EventMember eventMember5 = new EventMember(5L, event, "조커", false); + List eventMembers = List.of(eventMember1, eventMember2, eventMember3, eventMember4); + List bills = List.of( + Bill.create(event, "뽕족", 60_000L, eventMembers), + Bill.create(event, "인생네컷", 20_000L, eventMembers) + ); + List eventMembersReal = List.of(eventMember1, eventMember2, eventMember3, eventMember4, eventMember5); + MemberBillReport memberBillReport = MemberBillReport.create(eventMembersReal, bills); + + assertThat(memberBillReport.getReports()) + .containsAllEntriesOf( + Map.of( + eventMember1, 20_000L, + eventMember2, 20_000L, + eventMember3, 20_000L, + eventMember4, 20_000L, + eventMember5, 0L + ) + ); + } +} diff --git a/server/src/test/java/haengdong/domain/eventmember/UpdatedMembersTest.java b/server/src/test/java/haengdong/domain/eventmember/UpdatedMembersTest.java new file mode 100644 index 000000000..0c87c3727 --- /dev/null +++ b/server/src/test/java/haengdong/domain/eventmember/UpdatedMembersTest.java @@ -0,0 +1,123 @@ +package haengdong.domain.eventmember; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.assertThatCode; +import static org.assertj.core.api.Assertions.assertThatThrownBy; + +import java.util.List; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; +import haengdong.event.domain.event.Event; +import haengdong.event.domain.event.member.EventMember; +import haengdong.event.domain.event.member.UpdatedMembers; +import haengdong.common.exception.HaengdongException; + +class UpdatedMembersTest { + + @DisplayName("이벤트 이름들은 중복될 수 없다.") + @Test + void validateNameUnique() { + Event event = new Event("행동대장 회식", 1L, "1231415jaksdf"); + List eventMembers = List.of( + new EventMember(1L, event, "고구마", false), + new EventMember(2L, event, "감자", false), + new EventMember(3L, event, "감자", false) + ); + + assertThatThrownBy(() -> new UpdatedMembers(eventMembers)) + .isInstanceOf(HaengdongException.class) + .hasMessage("중복된 참여 인원 이름 변경 요청이 존재합니다."); + } + + @DisplayName("이벤트 회원들은 중복될 수 없다.") + @Test + void validateMemberUnique() { + Event event = new Event("행동대장 회식", 1L, "1231415jaksdf"); + EventMember eventMember1 = new EventMember(1L, event, "고구마", false); + EventMember eventMember2 = new EventMember(2L, event, "감자", false); + List eventMembers = List.of(eventMember1, eventMember2, eventMember2); + + + assertThatThrownBy(() -> new UpdatedMembers(eventMembers)) + .isInstanceOf(HaengdongException.class) + .hasMessage("중복된 참여 인원 이름 변경 요청이 존재합니다."); + } + + @DisplayName("이벤트 이름들로 이벤트 참여자들을 생성한다.") + @Test + void create() { + Event event = new Event("행동대장 회식", 1L, "1231415jaksdf"); + EventMember eventMember1 = new EventMember(1L, event, "고구마", false); + EventMember eventMember2 = new EventMember(2L, event, "감자", false); + EventMember eventMember3 = new EventMember(3L, event, "당근", false); + List eventMembers = List.of(eventMember1, eventMember2, eventMember3); + + UpdatedMembers eventUpdatedMembers = new UpdatedMembers(eventMembers); + assertThat(eventUpdatedMembers.getMembers()).hasSize(3) + .containsExactlyInAnyOrder(eventMember1, eventMember2, eventMember3); + } + + @DisplayName("이벤트의 참여자들 전체가 존재하지 않으면 업데이트할 수 없다.") + @Test + void validateUpdatedMembersExist() { + Event event = new Event("행동대장 회식", 1L, "1231415jaksdf"); + EventMember eventMember1 = new EventMember(1L, event, "고구마", false); + EventMember eventMember2 = new EventMember(2L, event, "감자", false); + EventMember eventMember3 = new EventMember(3L, event, "당근", false); + EventMember eventMember4 = new EventMember(4L, event, "양파", false); + List eventMembers = List.of(eventMember1, eventMember2, eventMember3, eventMember4); + + EventMember updateEventMember1 = new EventMember(1L, event, "토다리", false); + EventMember updateEventMember2 = new EventMember(2L, event, "쿠키", false); + EventMember updateEventMember3 = new EventMember(3L, event, "백호", false); + UpdatedMembers updatedMembers = new UpdatedMembers(List.of( + updateEventMember1, updateEventMember2, updateEventMember3)); + + assertThatThrownBy(() -> updatedMembers.validateUpdatable(eventMembers)) + .isInstanceOf(HaengdongException.class) + .hasMessage("업데이트 요청된 참여자 ID 목록과 기존 행사 참여자 ID 목록이 일치하지 않습니다."); + } + + @DisplayName("업데이트할 이름 중에 기존 이벤트의 참여자들의 이름과 중복되면 업데이트할 수 없다.") + @Test + void validateUpdatedNamesUnique() { + Event event = new Event("행동대장 회식", 1L, "1231415jaksdf"); + EventMember eventMember1 = new EventMember(1L, event, "고구마", false); + EventMember eventMember2 = new EventMember(2L, event, "감자", false); + EventMember eventMember3 = new EventMember(3L, event, "당근", false); + EventMember eventMember4 = new EventMember(4L, event, "양파", false); + List eventMembers = List.of(eventMember1, eventMember2, eventMember3, eventMember4); + + EventMember updateEventMember1 = new EventMember(1L, event, "토다리", false); + EventMember updateEventMember2 = new EventMember(2L, event, "쿠키", false); + EventMember updateEventMember3 = new EventMember(3L, event, "백호", false); + EventMember updateEventMember4 = new EventMember(4L, event, "감자", false); + UpdatedMembers updatedMembers = new UpdatedMembers(List.of( + updateEventMember1, updateEventMember2, updateEventMember3, updateEventMember4)); + + assertThatThrownBy(() -> updatedMembers.validateUpdatable(eventMembers)) + .isInstanceOf(HaengdongException.class) + .hasMessage("행사에 중복된 참여자 이름이 존재합니다."); + } + + @DisplayName("이벤트의 참여자들 전체를 업데이트 검증한다.") + @Test + void validateUpdatable() { + Event event = new Event("행동대장 회식", 1L, "1231415jaksdf"); + EventMember eventMember1 = new EventMember(1L, event, "고구마", false); + EventMember eventMember2 = new EventMember(2L, event, "감자", false); + EventMember eventMember3 = new EventMember(3L, event, "당근", false); + EventMember eventMember4 = new EventMember(4L, event, "양파", false); + List eventMembers = List.of(eventMember1, eventMember2, eventMember3, eventMember4); + + EventMember updateEventMember1 = new EventMember(1L, event, "토다리", false); + EventMember updateEventMember2 = new EventMember(2L, event, "쿠키", false); + EventMember updateEventMember3 = new EventMember(3L, event, "백호", false); + EventMember updateEventMember4 = new EventMember(4L, event, "망쵸", false); + UpdatedMembers updatedMembers = new UpdatedMembers(List.of( + updateEventMember1, updateEventMember2, updateEventMember3, updateEventMember4)); + + assertThatCode(() -> updatedMembers.validateUpdatable(eventMembers)) + .doesNotThrowAnyException(); + } +} diff --git a/server/src/test/java/haengdong/domain/step/StepTest.java b/server/src/test/java/haengdong/domain/step/StepTest.java new file mode 100644 index 000000000..d1dfa69a2 --- /dev/null +++ b/server/src/test/java/haengdong/domain/step/StepTest.java @@ -0,0 +1,51 @@ +package haengdong.domain.step; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.assertThatThrownBy; +import static haengdong.support.fixture.Fixture.EVENT1; + +import java.util.List; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; +import haengdong.event.domain.bill.Bill; +import haengdong.event.domain.event.member.EventMember; +import haengdong.event.domain.step.Step; +import haengdong.common.exception.HaengdongException; + +class StepTest { + + @DisplayName("회원 구성이 같은 지출은 Step에 추가될 수 있다.") + @Test + void add1() { + EventMember eventMember1 = new EventMember(1L, EVENT1, "감자", false); + EventMember eventMember2 = new EventMember(2L, EVENT1, "고구마", false); + EventMember eventMember3 = new EventMember(3L, EVENT1, "당근", false); + EventMember eventMember4 = new EventMember(4L, EVENT1, "양파", false); + Bill bill1 = Bill.create(EVENT1, "뽕족", 10_000L, List.of(eventMember1, eventMember2, eventMember3, eventMember4)); + Step step = Step.of(bill1); + + Bill bill2 = Bill.create(EVENT1, "인생네컷", 5_000L, List.of(eventMember2, eventMember3, eventMember1, eventMember4)); + + step.add(bill2); + + List bills = step.getBills(); + + assertThat(bills).hasSize(2); + } + + @DisplayName("회원 구성이 댜른 지출은 Step에 추가될 수 없다.") + @Test + void add2() { + EventMember eventMember1 = new EventMember(1L, EVENT1, "감자", false); + EventMember eventMember2 = new EventMember(2L, EVENT1, "고구마", false); + EventMember eventMember3 = new EventMember(3L, EVENT1, "당근", false); + EventMember eventMember4 = new EventMember(4L, EVENT1, "양파", false); + Bill bill1 = Bill.create(EVENT1, "뽕족", 10_000L, List.of(eventMember1, eventMember2, eventMember3, eventMember4)); + Step step = Step.of(bill1); + + Bill bill2 = Bill.create(EVENT1, "인생네컷", 5_000L, List.of(eventMember2, eventMember3, eventMember1)); + + assertThatThrownBy(() -> step.add(bill2)) + .isInstanceOf(HaengdongException.class); + } +} diff --git a/server/src/test/java/server/haengdong/domain/step/StepsTest.java b/server/src/test/java/haengdong/domain/step/StepsTest.java similarity index 57% rename from server/src/test/java/server/haengdong/domain/step/StepsTest.java rename to server/src/test/java/haengdong/domain/step/StepsTest.java index 799cb0d4c..33edb2124 100644 --- a/server/src/test/java/server/haengdong/domain/step/StepsTest.java +++ b/server/src/test/java/haengdong/domain/step/StepsTest.java @@ -1,29 +1,31 @@ -package server.haengdong.domain.step; +package haengdong.domain.step; import static org.assertj.core.api.Assertions.assertThat; import static org.junit.jupiter.api.Assertions.assertAll; -import static server.haengdong.support.fixture.Fixture.EVENT1; +import static haengdong.support.fixture.Fixture.EVENT1; import java.util.List; import org.junit.jupiter.api.DisplayName; import org.junit.jupiter.api.Test; -import server.haengdong.domain.bill.Bill; -import server.haengdong.domain.member.Member; +import haengdong.event.domain.bill.Bill; +import haengdong.event.domain.event.member.EventMember; +import haengdong.event.domain.step.Step; +import haengdong.event.domain.step.Steps; class StepsTest { @DisplayName("지출 목록 순으로 같은 회원 구성인 경우 같은 Step으로 묶는다.") @Test void of() { - Member member1 = new Member(1L, EVENT1, "감자", false); - Member member2 = new Member(2L, EVENT1, "고구마", false); - Member member3 = new Member(3L, EVENT1, "당근", false); - Member member4 = new Member(4L, EVENT1, "양파", false); - Bill bill1 = Bill.create(EVENT1, "뽕족", 10_000L, List.of(member1, member2)); - Bill bill2 = Bill.create(EVENT1, "용용선생", 20_000L, List.of(member2, member1)); - Bill bill3 = Bill.create(EVENT1, "보승회관", 30_000L, List.of(member1, member2, member3)); - Bill bill4 = Bill.create(EVENT1, "감자", 40_000L, List.of(member1, member2, member3, member4)); - Bill bill5 = Bill.create(EVENT1, "인생네컷", 5_000L, List.of(member2, member3, member1, member4)); + EventMember eventMember1 = new EventMember(1L, EVENT1, "감자", false); + EventMember eventMember2 = new EventMember(2L, EVENT1, "고구마", false); + EventMember eventMember3 = new EventMember(3L, EVENT1, "당근", false); + EventMember eventMember4 = new EventMember(4L, EVENT1, "양파", false); + Bill bill1 = Bill.create(EVENT1, "뽕족", 10_000L, List.of(eventMember1, eventMember2)); + Bill bill2 = Bill.create(EVENT1, "용용선생", 20_000L, List.of(eventMember2, eventMember1)); + Bill bill3 = Bill.create(EVENT1, "보승회관", 30_000L, List.of(eventMember1, eventMember2, eventMember3)); + Bill bill4 = Bill.create(EVENT1, "감자", 40_000L, List.of(eventMember1, eventMember2, eventMember3, eventMember4)); + Bill bill5 = Bill.create(EVENT1, "인생네컷", 5_000L, List.of(eventMember2, eventMember3, eventMember1, eventMember4)); List bills = List.of(bill1, bill2, bill3, bill4, bill5); Steps step = Steps.of(bills); @@ -34,15 +36,15 @@ void of() { () -> assertThat(steps.get(0).getBills()).hasSize(2) .containsExactly(bill1, bill2), () -> assertThat(steps.get(0).getMembers()).hasSize(2) - .containsExactly(member1, member2), + .containsExactly(eventMember1, eventMember2), () -> assertThat(steps.get(1).getBills()).hasSize(1) .containsExactly(bill3), () -> assertThat(steps.get(1).getMembers()).hasSize(3) - .containsExactly(member1, member2, member3), + .containsExactly(eventMember1, eventMember2, eventMember3), () -> assertThat(steps.get(2).getBills()).hasSize(2) .containsExactly(bill4, bill5), () -> assertThat(steps.get(2).getMembers()).hasSize(4) - .containsExactly(member1, member2, member3, member4) + .containsExactly(eventMember1, eventMember2, eventMember3, eventMember4) ); } } diff --git a/server/src/test/java/server/haengdong/presentation/BillControllerTest.java b/server/src/test/java/haengdong/presentation/BillControllerTest.java similarity index 81% rename from server/src/test/java/server/haengdong/presentation/BillControllerTest.java rename to server/src/test/java/haengdong/presentation/BillControllerTest.java index b6658d7b6..c8fe55ddf 100644 --- a/server/src/test/java/server/haengdong/presentation/BillControllerTest.java +++ b/server/src/test/java/haengdong/presentation/BillControllerTest.java @@ -1,4 +1,4 @@ -package server.haengdong.presentation; +package haengdong.presentation; import static org.mockito.ArgumentMatchers.anyLong; import static org.mockito.ArgumentMatchers.anyString; @@ -11,14 +11,14 @@ import java.util.List; import org.junit.jupiter.api.DisplayName; import org.junit.jupiter.api.Test; -import server.haengdong.application.response.BillAppResponse; -import server.haengdong.application.response.BillDetailAppResponse; -import server.haengdong.application.response.BillDetailsAppResponse; -import server.haengdong.application.response.MemberAppResponse; -import server.haengdong.application.response.StepAppResponse; -import server.haengdong.domain.bill.Bill; -import server.haengdong.domain.member.Member; -import server.haengdong.support.fixture.Fixture; +import haengdong.event.application.response.BillAppResponse; +import haengdong.event.application.response.BillDetailAppResponse; +import haengdong.event.application.response.BillDetailsAppResponse; +import haengdong.event.application.response.MemberAppResponse; +import haengdong.event.application.response.StepAppResponse; +import haengdong.event.domain.bill.Bill; +import haengdong.event.domain.event.member.EventMember; +import haengdong.support.fixture.Fixture; class BillControllerTest extends ControllerTestSupport { @@ -28,8 +28,8 @@ void findBills() throws Exception { Bill bill = Fixture.BILL1; List bills = List.of(BillAppResponse.of(bill)); - Member member = Fixture.MEMBER1; - List members = List.of(MemberAppResponse.of(member)); + EventMember eventMember = Fixture.EVENT_MEMBER_1; + List members = List.of(MemberAppResponse.of(eventMember)); StepAppResponse stepAppResponse = new StepAppResponse(bills, members); given(billService.findSteps(anyString())).willReturn(List.of(stepAppResponse)); @@ -44,8 +44,8 @@ void findBills() throws Exception { .andExpect(jsonPath("$.steps[0].bills[0].price").value(bill.getPrice())) .andExpect(jsonPath("$.steps[0].bills[0].isFixed").value(bill.isFixed())) .andExpect(jsonPath("$.steps[0].members").isArray()) - .andExpect(jsonPath("$.steps[0].members[0].id").value(member.getId())) - .andExpect(jsonPath("$.steps[0].members[0].name").value(member.getName())); + .andExpect(jsonPath("$.steps[0].members[0].id").value(eventMember.getId())) + .andExpect(jsonPath("$.steps[0].members[0].name").value(eventMember.getName())); } @DisplayName("참여자별 지출 금액을 조회한다.") diff --git a/server/src/test/java/server/haengdong/presentation/ControllerTestSupport.java b/server/src/test/java/haengdong/presentation/ControllerTestSupport.java similarity index 60% rename from server/src/test/java/server/haengdong/presentation/ControllerTestSupport.java rename to server/src/test/java/haengdong/presentation/ControllerTestSupport.java index 3d7763ee0..b855a061a 100644 --- a/server/src/test/java/server/haengdong/presentation/ControllerTestSupport.java +++ b/server/src/test/java/haengdong/presentation/ControllerTestSupport.java @@ -1,4 +1,4 @@ -package server.haengdong.presentation; +package haengdong.presentation; import com.fasterxml.jackson.databind.ObjectMapper; import org.springframework.beans.factory.annotation.Autowired; @@ -8,15 +8,18 @@ import org.springframework.context.annotation.FilterType; import org.springframework.test.web.servlet.MockMvc; import org.springframework.web.servlet.config.annotation.WebMvcConfigurer; -import server.haengdong.application.AuthService; -import server.haengdong.application.BillService; -import server.haengdong.application.EventImageFacadeService; -import server.haengdong.application.EventService; -import server.haengdong.application.ImageService; -import server.haengdong.application.MemberService; -import server.haengdong.presentation.admin.AdminBillController; -import server.haengdong.presentation.admin.AdminEventController; -import server.haengdong.presentation.admin.AdminMemberController; +import haengdong.common.auth.application.AuthService; +import haengdong.event.application.BillService; +import haengdong.event.application.EventImageFacadeService; +import haengdong.event.application.EventService; +import haengdong.event.application.EventMemberService; +import haengdong.user.application.UserService; +import haengdong.event.presentation.BillController; +import haengdong.event.presentation.EventController; +import haengdong.event.presentation.EventMemberController; +import haengdong.event.presentation.admin.AdminBillController; +import haengdong.event.presentation.admin.AdminEventController; +import haengdong.event.presentation.admin.AdminMemberController; @WebMvcTest( controllers = { @@ -24,7 +27,7 @@ AdminBillController.class, AdminMemberController.class, EventController.class, - MemberController.class, + EventMemberController.class, BillController.class }, excludeFilters = {@ComponentScan.Filter(type = FilterType.ASSIGNABLE_TYPE, classes = {WebMvcConfigurer.class})} @@ -44,11 +47,14 @@ public abstract class ControllerTestSupport { protected AuthService authService; @MockBean - protected MemberService memberService; + protected EventMemberService eventMemberService; @MockBean protected BillService billService; @MockBean protected EventImageFacadeService eventImageFacadeService; + + @MockBean + protected UserService userService; } diff --git a/server/src/test/java/server/haengdong/presentation/EventControllerTest.java b/server/src/test/java/haengdong/presentation/EventControllerTest.java similarity index 71% rename from server/src/test/java/server/haengdong/presentation/EventControllerTest.java rename to server/src/test/java/haengdong/presentation/EventControllerTest.java index 90e7fd618..50abe3614 100644 --- a/server/src/test/java/server/haengdong/presentation/EventControllerTest.java +++ b/server/src/test/java/haengdong/presentation/EventControllerTest.java @@ -1,4 +1,4 @@ -package server.haengdong.presentation; +package haengdong.presentation; import static org.hamcrest.Matchers.equalTo; import static org.mockito.ArgumentMatchers.any; @@ -16,13 +16,12 @@ import org.springframework.http.MediaType; import org.springframework.restdocs.mockmvc.RestDocumentationRequestBuilders; import org.springframework.test.web.servlet.result.MockMvcResultMatchers; -import server.haengdong.application.request.EventAppRequest; -import server.haengdong.application.response.EventAppResponse; -import server.haengdong.application.response.EventDetailAppResponse; -import server.haengdong.application.response.EventImageAppResponse; -import server.haengdong.application.response.MemberBillReportAppResponse; -import server.haengdong.presentation.request.EventLoginRequest; -import server.haengdong.presentation.request.EventSaveRequest; +import haengdong.event.application.request.EventGuestAppRequest; +import haengdong.event.application.response.EventAppResponse; +import haengdong.event.application.response.EventDetailAppResponse; +import haengdong.event.application.response.EventImageAppResponse; +import haengdong.event.application.response.MemberBillReportAppResponse; +import haengdong.event.presentation.request.EventGuestSaveRequest; class EventControllerTest extends ControllerTestSupport { @@ -31,7 +30,7 @@ class EventControllerTest extends ControllerTestSupport { @Test void findEventTest() throws Exception { String eventId = "망쵸토큰"; - EventDetailAppResponse eventDetailAppResponse = new EventDetailAppResponse("행동대장 회식", "토스뱅크", "1231245"); + EventDetailAppResponse eventDetailAppResponse = new EventDetailAppResponse("행동대장 회식", "토스뱅크", "1231245", true); given(eventService.findEvent(eventId)).willReturn(eventDetailAppResponse); mockMvc.perform(get("/api/events/{eventId}", eventId)) @@ -66,41 +65,24 @@ void getMemberBillReports() throws Exception { @DisplayName("이벤트를 생성한다.") @Test - void saveEvent() throws Exception { - EventSaveRequest eventSaveRequest = new EventSaveRequest("토다리", "0987"); + void saveEventGuest() throws Exception { + EventGuestSaveRequest eventSaveRequest = new EventGuestSaveRequest("토다리", "nick", "0987"); String requestBody = objectMapper.writeValueAsString(eventSaveRequest); String eventId = "망쵸토큰"; - EventAppResponse eventAppResponse = new EventAppResponse(eventId); - given(eventService.saveEvent(any(EventAppRequest.class))).willReturn(eventAppResponse); - given(authService.createToken(eventId)).willReturn("jwtToken"); - given(authService.getTokenName()).willReturn("eventToken"); + EventAppResponse eventAppResponse = new EventAppResponse(eventId, 1L); + given(eventService.saveEventGuest(any(EventGuestAppRequest.class))).willReturn(eventAppResponse); + given(authService.createGuestToken(1L)).willReturn("jwtToken"); + given(authService.getTokenName()).willReturn("accessToken"); - mockMvc.perform(post("/api/events") + mockMvc.perform(post("/api/events/guest") .contentType(MediaType.APPLICATION_JSON) .content(requestBody)) .andDo(print()) .andExpect(status().isOk()) - .andExpect(cookie().value("eventToken", "jwtToken")) + .andExpect(cookie().value("accessToken", "jwtToken")) .andExpect(jsonPath("$.eventId").value("망쵸토큰")); } - @DisplayName("행사 어드민이 로그인한다.") - @Test - void loginEvent() throws Exception { - String token = "TOKEN"; - EventLoginRequest eventLoginRequest = new EventLoginRequest("1234"); - String requestBody = objectMapper.writeValueAsString(eventLoginRequest); - given(authService.createToken(token)).willReturn("jwtToken"); - given(authService.getTokenName()).willReturn("eventToken"); - - mockMvc.perform(post("/api/events/{eventId}/login", token) - .contentType(MediaType.APPLICATION_JSON) - .content(requestBody)) - .andDo(print()) - .andExpect(cookie().value("eventToken", "jwtToken")) - .andExpect(status().isOk()); - } - @DisplayName("행사 이미지를 조회한다.") @Test void findAllImages() throws Exception { diff --git a/server/src/test/java/haengdong/presentation/EventEventMemberControllerTest.java b/server/src/test/java/haengdong/presentation/EventEventMemberControllerTest.java new file mode 100644 index 000000000..aedb5b0ef --- /dev/null +++ b/server/src/test/java/haengdong/presentation/EventEventMemberControllerTest.java @@ -0,0 +1,77 @@ +package haengdong.presentation; + +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.anyString; +import static org.mockito.BDDMockito.given; +import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get; +import static org.springframework.test.web.servlet.result.MockMvcResultHandlers.print; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.jsonPath; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; +import static haengdong.support.fixture.Fixture.EVENT_MEMBER_1; +import static haengdong.support.fixture.Fixture.EVENT_MEMBER_2; +import static haengdong.support.fixture.Fixture.EVENT_MEMBER_3; + +import java.util.List; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; +import org.springframework.http.MediaType; +import haengdong.event.application.response.MemberAppResponse; +import haengdong.event.application.response.MemberDepositAppResponse; +import haengdong.event.application.response.MembersDepositAppResponse; +import haengdong.event.domain.event.member.EventMember; + +class EventEventMemberControllerTest extends ControllerTestSupport { + + @DisplayName("행사에 참여한 전체 인원을 조회한다.") + @Test + void findAllMembersTest() throws Exception { + EventMember eventMember1 = EVENT_MEMBER_1; + EventMember eventMember2 = EVENT_MEMBER_2; + EventMember eventMember3 = EVENT_MEMBER_3; + List members = List.of( + MemberDepositAppResponse.of(eventMember1), + MemberDepositAppResponse.of(eventMember2), + MemberDepositAppResponse.of(eventMember3) + ); + + MembersDepositAppResponse memberAppResponse = new MembersDepositAppResponse(members); + given(eventMemberService.findAllMembers(anyString())).willReturn(memberAppResponse); + + mockMvc.perform(get("/api/events/{eventId}/members", "TOKEN")) + .andDo(print()) + .andExpect(status().isOk()) + .andExpect(jsonPath("$.members").isArray()) + .andExpect(jsonPath("$.members[0].id").value(eventMember1.getId())) + .andExpect(jsonPath("$.members[0].name").value(eventMember1.getName())) + .andExpect(jsonPath("$.members[0].isDeposited").value(eventMember1.isDeposited())) + .andExpect(jsonPath("$.members[1].id").value(eventMember2.getId())) + .andExpect(jsonPath("$.members[1].name").value(eventMember2.getName())) + .andExpect(jsonPath("$.members[1].isDeposited").value(eventMember2.isDeposited())) + .andExpect(jsonPath("$.members[2].id").value(eventMember3.getId())) + .andExpect(jsonPath("$.members[2].name").value(eventMember3.getName())) + .andExpect(jsonPath("$.members[2].isDeposited").value(eventMember3.isDeposited())); + } + + @DisplayName("현재 참여 인원을 조회합니다.") + @Test + void getCurrentMembers() throws Exception { + EventMember eventMember1 = EVENT_MEMBER_1; + EventMember eventMember2 = EVENT_MEMBER_2; + List members = List.of( + MemberAppResponse.of(eventMember1), + MemberAppResponse.of(eventMember2) + ); + + given(eventMemberService.getCurrentMembers(any())).willReturn(members); + + mockMvc.perform(get("/api/events/{eventId}/members/current", "TOKEN") + .accept(MediaType.APPLICATION_JSON)) + .andDo(print()) + .andExpect(status().isOk()) + .andExpect(jsonPath("$.members").isArray()) + .andExpect(jsonPath("$.members[0].id").value(eventMember1.getId())) + .andExpect(jsonPath("$.members[0].name").value(eventMember1.getName())) + .andExpect(jsonPath("$.members[1].id").value(eventMember2.getId())) + .andExpect(jsonPath("$.members[1].name").value(eventMember2.getName())); + } +} diff --git a/server/src/test/java/server/haengdong/presentation/admin/AdminBillControllerTest.java b/server/src/test/java/haengdong/presentation/admin/AdminBillControllerTest.java similarity index 88% rename from server/src/test/java/server/haengdong/presentation/admin/AdminBillControllerTest.java rename to server/src/test/java/haengdong/presentation/admin/AdminBillControllerTest.java index e3599a9ee..32ec84ffc 100644 --- a/server/src/test/java/server/haengdong/presentation/admin/AdminBillControllerTest.java +++ b/server/src/test/java/haengdong/presentation/admin/AdminBillControllerTest.java @@ -1,4 +1,4 @@ -package server.haengdong.presentation.admin; +package haengdong.presentation.admin; import static org.mockito.ArgumentMatchers.any; @@ -8,19 +8,19 @@ import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post; import static org.springframework.test.web.servlet.result.MockMvcResultHandlers.print; import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; -import static server.haengdong.support.fixture.Fixture.EVENT_COOKIE; +import static haengdong.support.fixture.Fixture.EVENT_COOKIE; import java.util.List; import org.junit.jupiter.api.DisplayName; import org.junit.jupiter.api.Test; import org.springframework.http.MediaType; -import server.haengdong.exception.HaengdongErrorCode; -import server.haengdong.exception.HaengdongException; -import server.haengdong.presentation.ControllerTestSupport; -import server.haengdong.presentation.request.BillDetailUpdateRequest; -import server.haengdong.presentation.request.BillDetailsUpdateRequest; -import server.haengdong.presentation.request.BillSaveRequest; -import server.haengdong.presentation.request.BillUpdateRequest; +import haengdong.common.exception.HaengdongErrorCode; +import haengdong.common.exception.HaengdongException; +import haengdong.presentation.ControllerTestSupport; +import haengdong.event.presentation.request.BillDetailUpdateRequest; +import haengdong.event.presentation.request.BillDetailsUpdateRequest; +import haengdong.event.presentation.request.BillSaveRequest; +import haengdong.event.presentation.request.BillUpdateRequest; class AdminBillControllerTest extends ControllerTestSupport { diff --git a/server/src/test/java/server/haengdong/presentation/admin/AdminEventControllerTest.java b/server/src/test/java/haengdong/presentation/admin/AdminEventControllerTest.java similarity index 86% rename from server/src/test/java/server/haengdong/presentation/admin/AdminEventControllerTest.java rename to server/src/test/java/haengdong/presentation/admin/AdminEventControllerTest.java index e071d70d3..cb13b1ad6 100644 --- a/server/src/test/java/server/haengdong/presentation/admin/AdminEventControllerTest.java +++ b/server/src/test/java/haengdong/presentation/admin/AdminEventControllerTest.java @@ -1,17 +1,17 @@ -package server.haengdong.presentation.admin; +package haengdong.presentation.admin; import static org.springframework.restdocs.mockmvc.RestDocumentationRequestBuilders.multipart; import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.patch; import static org.springframework.test.web.servlet.result.MockMvcResultHandlers.print; import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; -import static server.haengdong.support.fixture.Fixture.EVENT_COOKIE; +import static haengdong.support.fixture.Fixture.EVENT_COOKIE; import org.junit.jupiter.api.DisplayName; import org.junit.jupiter.api.Test; import org.springframework.http.MediaType; import org.springframework.mock.web.MockMultipartFile; -import server.haengdong.presentation.ControllerTestSupport; -import server.haengdong.presentation.request.EventUpdateRequest; +import haengdong.presentation.ControllerTestSupport; +import haengdong.event.presentation.request.EventUpdateRequest; class AdminEventControllerTest extends ControllerTestSupport { @@ -20,7 +20,7 @@ class AdminEventControllerTest extends ControllerTestSupport { @Test void updateEventTest() throws Exception { String token = "TOKEN"; - EventUpdateRequest eventUpdateRequest = new EventUpdateRequest("행동대장 비대위", "행대뱅크", "12345678"); + EventUpdateRequest eventUpdateRequest = new EventUpdateRequest("행동대장 비대위"); String requestBody = objectMapper.writeValueAsString(eventUpdateRequest); diff --git a/server/src/test/java/server/haengdong/presentation/admin/AdminMemberControllerTest.java b/server/src/test/java/haengdong/presentation/admin/AdminEventEventMemberControllerTest.java similarity index 82% rename from server/src/test/java/server/haengdong/presentation/admin/AdminMemberControllerTest.java rename to server/src/test/java/haengdong/presentation/admin/AdminEventEventMemberControllerTest.java index 6afb013f9..e1c35f8ff 100644 --- a/server/src/test/java/server/haengdong/presentation/admin/AdminMemberControllerTest.java +++ b/server/src/test/java/haengdong/presentation/admin/AdminEventEventMemberControllerTest.java @@ -1,4 +1,4 @@ -package server.haengdong.presentation.admin; +package haengdong.presentation.admin; import static org.hamcrest.Matchers.equalTo; import static org.mockito.BDDMockito.given; @@ -7,22 +7,22 @@ import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.put; import static org.springframework.test.web.servlet.result.MockMvcResultHandlers.print; import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; -import static server.haengdong.support.fixture.Fixture.EVENT_COOKIE; +import static haengdong.support.fixture.Fixture.EVENT_COOKIE; import java.util.List; import org.junit.jupiter.api.DisplayName; import org.junit.jupiter.api.Test; import org.springframework.http.MediaType; import org.springframework.test.web.servlet.result.MockMvcResultMatchers; -import server.haengdong.application.response.MemberSaveAppResponse; -import server.haengdong.application.response.MembersSaveAppResponse; -import server.haengdong.presentation.ControllerTestSupport; -import server.haengdong.presentation.request.MemberSaveRequest; -import server.haengdong.presentation.request.MemberUpdateRequest; -import server.haengdong.presentation.request.MembersSaveRequest; -import server.haengdong.presentation.request.MembersUpdateRequest; +import haengdong.event.application.response.MemberSaveAppResponse; +import haengdong.event.application.response.MembersSaveAppResponse; +import haengdong.presentation.ControllerTestSupport; +import haengdong.event.presentation.request.MemberSaveRequest; +import haengdong.event.presentation.request.MemberUpdateRequest; +import haengdong.event.presentation.request.MembersSaveRequest; +import haengdong.event.presentation.request.MembersUpdateRequest; -class AdminMemberControllerTest extends ControllerTestSupport { +class AdminEventEventMemberControllerTest extends ControllerTestSupport { @DisplayName("행사 참여자를 추가한다.") @Test @@ -41,7 +41,7 @@ void saveMemberTest() throws Exception { new MemberSaveAppResponse(2L, "소하") ) ); - given(memberService.saveMembers(eventToken, membersSaveRequest.toAppRequest())) + given(eventMemberService.saveMembers(eventToken, membersSaveRequest.toAppRequest())) .willReturn(appResponse); mockMvc.perform(post("/api/admin/events/{eventId}/members", "망쵸토큰") diff --git a/server/src/test/java/server/haengdong/support/extension/DatabaseCleaner.java b/server/src/test/java/haengdong/support/extension/DatabaseCleaner.java similarity index 97% rename from server/src/test/java/server/haengdong/support/extension/DatabaseCleaner.java rename to server/src/test/java/haengdong/support/extension/DatabaseCleaner.java index 346e81d2d..bc069869a 100644 --- a/server/src/test/java/server/haengdong/support/extension/DatabaseCleaner.java +++ b/server/src/test/java/haengdong/support/extension/DatabaseCleaner.java @@ -1,4 +1,4 @@ -package server.haengdong.support.extension; +package haengdong.support.extension; import jakarta.annotation.PostConstruct; import jakarta.persistence.EntityManager; diff --git a/server/src/test/java/server/haengdong/support/extension/DatabaseCleanerExtension.java b/server/src/test/java/haengdong/support/extension/DatabaseCleanerExtension.java similarity index 93% rename from server/src/test/java/server/haengdong/support/extension/DatabaseCleanerExtension.java rename to server/src/test/java/haengdong/support/extension/DatabaseCleanerExtension.java index 653ecadb3..5cd9bcc99 100644 --- a/server/src/test/java/server/haengdong/support/extension/DatabaseCleanerExtension.java +++ b/server/src/test/java/haengdong/support/extension/DatabaseCleanerExtension.java @@ -1,4 +1,4 @@ -package server.haengdong.support.extension; +package haengdong.support.extension; import org.junit.jupiter.api.extension.AfterEachCallback; import org.junit.jupiter.api.extension.ExtensionContext; diff --git a/server/src/test/java/haengdong/support/fixture/Fixture.java b/server/src/test/java/haengdong/support/fixture/Fixture.java new file mode 100644 index 000000000..97ea6c1ef --- /dev/null +++ b/server/src/test/java/haengdong/support/fixture/Fixture.java @@ -0,0 +1,18 @@ +package haengdong.support.fixture; + +import jakarta.servlet.http.Cookie; +import haengdong.event.domain.bill.Bill; +import haengdong.event.domain.event.member.EventMember; +import haengdong.event.domain.event.Event; + +public class Fixture { + + public static final Event EVENT1 = new Event("쿠키", 1L, "TOKEN1"); + public static final Event EVENT2 = new Event("웨디", 1L, "TOKEN2"); + public static final Cookie EVENT_COOKIE = new Cookie("accessToken", "토큰토큰"); + public static final EventMember EVENT_MEMBER_1 = new EventMember(EVENT1, "토다리"); + public static final EventMember EVENT_MEMBER_2 = new EventMember(EVENT1, "쿠키"); + public static final EventMember EVENT_MEMBER_3 = new EventMember(EVENT1, "소하"); + public static final Bill BILL1 = new Bill(EVENT1, "행동대장 회식", 10000L); + public static final Bill BILL2 = new Bill(EVENT2, "행동대장 회식2", 20000L); +} diff --git a/server/src/test/java/haengdong/user/domain/UserTest.java b/server/src/test/java/haengdong/user/domain/UserTest.java new file mode 100644 index 000000000..c739df0e4 --- /dev/null +++ b/server/src/test/java/haengdong/user/domain/UserTest.java @@ -0,0 +1,103 @@ +package haengdong.user.domain; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.assertThatCode; +import static org.assertj.core.api.Assertions.assertThatThrownBy; +import static org.junit.jupiter.api.Assertions.assertAll; + +import haengdong.common.exception.HaengdongException; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.ValueSource; + +class UserTest { + + @DisplayName("계좌 정보에 은행 이름과 계좌 번호가 모두 포함된다.") + @Test + void changeAccountTest() { + User user = User.createGuest("이름", "1234"); + + user.changeAccount("토스뱅크", "12345678"); + + assertAll( + () -> assertThat(user.getBank()).isEqualTo("토스뱅크"), + () -> assertThat(user.getAccountNumber()).isEqualTo("12345678") + ); + } + + @DisplayName("계좌 정보에 은행 이름과 계좌 번호가 모두 포함되지 않으면 예외가 발생한다.") + @Test + void changeAccountTest1() { + User user = User.createGuest("이름", "1234"); + + assertThatThrownBy(() -> user.changeAccount("행대뱅크", "")) + .isInstanceOf(HaengdongException.class); + } + + @DisplayName("지원하는 은행이면 예외가 발생하지 않는다.") + @ParameterizedTest + @ValueSource(strings = {"토스뱅크", "KB국민은행"}) + void changeAccountTest2(String bankName) { + User user = User.createGuest("이름", "1234"); + + assertThatCode(() -> user.changeAccount(bankName, "12345678")) + .doesNotThrowAnyException(); + } + + @DisplayName("지원하지 않는 은행이면 예외가 발생한다.") + @ParameterizedTest + @ValueSource(strings = {"행대뱅크", "토스 뱅크", "망쵸뱅크", "KB 국민은행"}) + void changeAccountTest3(String bankName) { + User user = User.createGuest("이름", "1234"); + + assertThatThrownBy(() -> user.changeAccount(bankName, "12345678")) + .isInstanceOf(HaengdongException.class); + } + + @DisplayName("계좌 번호가 8자 이상 30자 이하면 예외가 발생하지 않는다.") + @ParameterizedTest + @ValueSource(strings = {"12345678", "123456789012345678901234567890"}) + void changeAccountTest4(String accountNumber) { + User user = User.createGuest("이름", "1234"); + + assertThatCode(() -> user.changeAccount("토스뱅크", accountNumber)) + .doesNotThrowAnyException(); + } + + @DisplayName("계좌 번호가 8자 미만 30자 초과면 예외가 발생한다.") + @ParameterizedTest + @ValueSource(strings = {"", " ", "1234567", "1234567890123456789012345678901"}) + void changeAccountTest5(String accountNumber) { + User user = User.createGuest("이름", "1234"); + + assertThatThrownBy(() -> user.changeAccount("토스뱅크", accountNumber)) + .isInstanceOf(HaengdongException.class); + } + + @DisplayName("계좌 정보를 조회한다.") + @Test + void getBankNameTest() { + User user = User.createGuest("이름", "1234"); + + user.changeAccount("토스뱅크", "12345678"); + + assertAll( + () -> assertThat(user.getBank()).isEqualTo("토스뱅크"), + () -> assertThat(user.getAccountNumber()).isEqualTo("12345678") + ); + } + + @DisplayName("계좌 번호에 공백이 있어도 계좌 정보를 정상적으로 조회한다.") + @Test + void getBankNameTest1() { + User user = User.createGuest("이름", "1234"); + + user.changeAccount("토스뱅크", "1234 5678 9012"); + + assertAll( + () -> assertThat(user.getBank()).isEqualTo("토스뱅크"), + () -> assertThat(user.getAccountNumber()).isEqualTo("1234 5678 9012") + ); + } +} diff --git a/server/src/test/java/server/haengdong/application/EventServiceTest.java b/server/src/test/java/server/haengdong/application/EventServiceTest.java deleted file mode 100644 index a1607c79f..000000000 --- a/server/src/test/java/server/haengdong/application/EventServiceTest.java +++ /dev/null @@ -1,247 +0,0 @@ -package server.haengdong.application; - - -import static org.assertj.core.api.Assertions.assertThat; -import static org.assertj.core.api.Assertions.assertThatThrownBy; -import static org.assertj.core.api.AssertionsForClassTypes.tuple; -import static org.junit.jupiter.api.Assertions.assertAll; -import static org.mockito.BDDMockito.given; - -import java.util.List; -import org.junit.jupiter.api.DisplayName; -import org.junit.jupiter.api.Test; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.beans.factory.annotation.Value; -import org.springframework.boot.test.mock.mockito.MockBean; -import server.haengdong.application.request.EventAppRequest; -import server.haengdong.application.request.EventUpdateAppRequest; -import server.haengdong.application.response.EventAppResponse; -import server.haengdong.application.response.EventDetailAppResponse; -import server.haengdong.application.response.EventImageAppResponse; -import server.haengdong.application.response.MemberBillReportAppResponse; -import server.haengdong.domain.RandomValueProvider; -import server.haengdong.domain.bill.Bill; -import server.haengdong.domain.bill.BillRepository; -import server.haengdong.domain.event.EventImage; -import server.haengdong.domain.event.EventImageRepository; -import server.haengdong.domain.member.Member; -import server.haengdong.domain.member.MemberRepository; -import server.haengdong.domain.event.Event; -import server.haengdong.domain.event.EventRepository; -import server.haengdong.exception.HaengdongException; -import server.haengdong.support.fixture.Fixture; - -class EventServiceTest extends ServiceTestSupport { - - @Autowired - private EventService eventService; - - @Autowired - private EventRepository eventRepository; - - @Autowired - private BillRepository billRepository; - - @Autowired - private MemberRepository memberRepository; - - @Autowired - private EventImageRepository eventImageRepository; - - @MockBean - private RandomValueProvider randomValueProvider; - - @Value("${image.base-url}") - private String baseUrl; - - @DisplayName("행사를 생성한다") - @Test - void saveEventTest() { - EventAppRequest request = new EventAppRequest("test", "1234"); - given(randomValueProvider.createRandomValue()).willReturn("TOKEN"); - - EventAppResponse response = eventService.saveEvent(request); - - assertThat(response.token()).isEqualTo("TOKEN"); - } - - @DisplayName("토큰으로 행사를 조회한다.") - @Test - void findEventTest() { - Event event = Fixture.EVENT1; - eventRepository.save(event); - - EventDetailAppResponse eventDetailAppResponse = eventService.findEvent(event.getToken()); - - assertThat(eventDetailAppResponse.eventName()).isEqualTo(event.getName()); - } - - @DisplayName("행사 정보를 수정한다.") - @Test - void updateEventTest() { - Event event = new Event("행동대장 비대위", "1234", "token"); - eventRepository.save(event); - - EventUpdateAppRequest eventUpdateAppRequest = new EventUpdateAppRequest("새로운 행사 이름", "토스뱅크", "12345678"); - eventService.updateEvent(event.getToken(), eventUpdateAppRequest); - - Event updateEvent = eventRepository.findByToken(event.getToken()).get(); - assertAll( - () -> assertThat(updateEvent.getName()).isEqualTo("새로운 행사 이름"), - () -> assertThat(updateEvent.getBankName()).isEqualTo("토스뱅크"), - () -> assertThat(updateEvent.getAccountNumber()).isEqualTo("12345678") - ); - } - - @DisplayName("행사의 은행 정보만 수정한다.") - @Test - void updateEventTest1() { - Event event = new Event("행동대장 비대위", "1234", "token"); - eventRepository.save(event); - - EventUpdateAppRequest eventUpdateAppRequest = new EventUpdateAppRequest(null, "토스뱅크", "12345678"); - eventService.updateEvent(event.getToken(), eventUpdateAppRequest); - - Event updateEvent = eventRepository.findByToken(event.getToken()).get(); - assertAll( - () -> assertThat(updateEvent.getName()).isEqualTo("행동대장 비대위"), - () -> assertThat(updateEvent.getBankName()).isEqualTo("토스뱅크"), - () -> assertThat(updateEvent.getAccountNumber()).isEqualTo("12345678") - ); - } - - @DisplayName("행사의 이름만 수정한다.") - @Test - void updateEventTest2() { - Event event = new Event("행동대장 비대위", "1234", "token"); - eventRepository.save(event); - - EventUpdateAppRequest eventUpdateAppRequest = new EventUpdateAppRequest("행동대장 정상 영업", null, null); - eventService.updateEvent(event.getToken(), eventUpdateAppRequest); - - Event updateEvent = eventRepository.findByToken(event.getToken()).get(); - assertAll( - () -> assertThat(updateEvent.getName()).isEqualTo("행동대장 정상 영업"), - () -> assertThat(updateEvent.getBankName()).isEqualTo(""), - () -> assertThat(updateEvent.getAccountNumber()).isEqualTo("") - ); - } - - @DisplayName("행사의 계좌 정보 일부가 누락되면 변경하지 않는다.") - @Test - void updateEventTest3() { - Event event = new Event("행동대장 비대위", "1234", "token"); - eventRepository.save(event); - - EventUpdateAppRequest eventUpdateAppRequest = new EventUpdateAppRequest(null, "망쵸뱅크", null); - eventService.updateEvent(event.getToken(), eventUpdateAppRequest); - - Event updateEvent = eventRepository.findByToken(event.getToken()).get(); - assertAll( - () -> assertThat(updateEvent.getName()).isEqualTo("행동대장 비대위"), - () -> assertThat(updateEvent.getBankName()).isEqualTo(""), - () -> assertThat(updateEvent.getAccountNumber()).isEqualTo("") - ); - } - - @DisplayName("참여자별 정산 현황을 조회한다.") - @Test - void getMemberBillReports() { - Event event = Fixture.EVENT1; - Event savedEvent = eventRepository.save(event); - List members = List.of( - new Member(savedEvent, "소하"), - new Member(savedEvent, "감자"), - new Member(savedEvent, "쿠키"), - new Member(savedEvent, "고구마") - ); - memberRepository.saveAll(members); - List bills = List.of( - Bill.create(savedEvent, "뽕족", 60_000L, members), - Bill.create(savedEvent, "인생네컷", 20_000L, members) - ); - billRepository.saveAll(bills); - - List responses = eventService.getMemberBillReports(event.getToken()); - - assertThat(responses) - .hasSize(4) - .extracting(MemberBillReportAppResponse::name, MemberBillReportAppResponse::price) - .containsExactlyInAnyOrder( - tuple("감자", 20_000L), - tuple("쿠키", 20_000L), - tuple("소하", 20_000L), - tuple("고구마", 20_000L) - ); - } - - @DisplayName("행사 이미지를 조회한다.") - @Test - void findAllImages() { - Event event = Fixture.EVENT1; - List eventImages = List.of( - new EventImage(event, "image1.jpg"), - new EventImage(event, "image2.jpg") - ); - eventRepository.save(event); - eventImageRepository.saveAll(eventImages); - - List responses = eventService.findImages(event.getToken()); - - assertThat(responses) - .hasSize(2) - .extracting(EventImageAppResponse::url) - .containsExactlyInAnyOrder( - baseUrl + "image1.jpg", - baseUrl + "image2.jpg" - ); - } - - @DisplayName("행사 이미지를 저장한다.") - @Test - void saveImages() { - Event event = Fixture.EVENT1; - eventRepository.save(event); - List imageNames = List.of("image1.jpg", "image2.jpg"); - given(randomValueProvider.createRandomValue()).willReturn("1234"); - - eventService.saveImages(event.getToken(), imageNames); - - List savedEventImages = eventImageRepository.findAllByEvent(event); - assertThat(savedEventImages) - .hasSize(2) - .extracting(EventImage::getName) - .containsExactlyInAnyOrder( - "1234image1.jpg", - "1234image2.jpg" - ); - } - - @DisplayName("행사 이미지를 삭제한다.") - @Test - void deleteImage() { - Event event = Fixture.EVENT1; - eventRepository.save(event); - EventImage eventImage = new EventImage(event, "image1.jpg"); - eventImageRepository.save(eventImage); - - eventService.deleteImage(event.getToken(), eventImage.getId()); - - assertThat(eventImageRepository.findById(eventImage.getId())) - .isEmpty(); - } - - @DisplayName("행사 1개당 이미지는 10개까지 업로드 가능하다.") - @Test - void validateImageCount() { - Event event = Fixture.EVENT1; - eventRepository.save(event); - List imageNames = List.of("image1.jpg", "image2.jpg"); - String token = event.getToken(); - eventService.saveImages(token, imageNames); - - assertThatThrownBy( - () -> eventService.saveImages(token, List.of("1", "2", "3", "4", "5", "6", "7", "8", "9"))) - .isInstanceOf(HaengdongException.class); - } -} diff --git a/server/src/test/java/server/haengdong/config/AdminInterceptorTest.java b/server/src/test/java/server/haengdong/config/AdminInterceptorTest.java deleted file mode 100644 index f66da7fd1..000000000 --- a/server/src/test/java/server/haengdong/config/AdminInterceptorTest.java +++ /dev/null @@ -1,56 +0,0 @@ -package server.haengdong.config; - -import static org.assertj.core.api.Assertions.assertThat; -import static org.assertj.core.api.Assertions.assertThatThrownBy; -import static org.mockito.ArgumentMatchers.any; -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.when; - -import org.junit.jupiter.api.BeforeEach; -import org.junit.jupiter.api.DisplayName; -import org.junit.jupiter.params.ParameterizedTest; -import org.junit.jupiter.params.provider.ValueSource; -import org.springframework.mock.web.MockHttpServletRequest; -import org.springframework.mock.web.MockHttpServletResponse; -import server.haengdong.application.AuthService; -import server.haengdong.exception.AuthenticationException; -import server.haengdong.infrastructure.auth.AuthenticationExtractor; - -class AdminInterceptorTest { - - private AuthService authService; - private AuthenticationExtractor authenticationExtractor; - private AdminInterceptor adminInterceptor; - - @BeforeEach - public void setUp() { - authService = mock(AuthService.class); - authenticationExtractor = mock(AuthenticationExtractor.class); - adminInterceptor = new AdminInterceptor(authService, authenticationExtractor); - } - - @DisplayName("쿠키의 JWT 에서 eventToken 과 uri 의 eventToken 이 일치하면 관리자이다.") - @ParameterizedTest - @ValueSource(strings = {"/api/admin/events/12345", "/api/admin/events/12345/bills"}) - void validateToken1(String uri) { - MockHttpServletRequest request = new MockHttpServletRequest("GET", uri); - MockHttpServletResponse response = new MockHttpServletResponse(); - when(authService.findEventIdByToken(any())).thenReturn("12345"); - - boolean preHandle = adminInterceptor.preHandle(request, response, new Object()); - - assertThat(preHandle).isTrue(); - } - - @DisplayName("쿠키의 JWT 에서 eventToken 과 uri 의 eventToken 이 일치하지 않으면 거절당한다.") - @ParameterizedTest - @ValueSource(strings = {"/api/admin/events/12345", "/api/admin/events/12345/bills"}) - void validateToken2(String uri) { - MockHttpServletRequest request = new MockHttpServletRequest("GET", uri); - MockHttpServletResponse response = new MockHttpServletResponse(); - when(authService.findEventIdByToken(any())).thenReturn("125"); - - assertThatThrownBy(() -> adminInterceptor.preHandle(request, response, new Object())) - .isInstanceOf(AuthenticationException.class); - } -} diff --git a/server/src/test/java/server/haengdong/domain/event/EventTest.java b/server/src/test/java/server/haengdong/domain/event/EventTest.java deleted file mode 100644 index 67c5420b0..000000000 --- a/server/src/test/java/server/haengdong/domain/event/EventTest.java +++ /dev/null @@ -1,165 +0,0 @@ -package server.haengdong.domain.event; - -import static org.assertj.core.api.Assertions.assertThat; -import static org.assertj.core.api.Assertions.assertThatCode; -import static org.assertj.core.api.Assertions.assertThatThrownBy; -import static org.junit.jupiter.api.Assertions.assertAll; - -import org.junit.jupiter.api.DisplayName; -import org.junit.jupiter.api.Test; -import org.junit.jupiter.params.ParameterizedTest; -import org.junit.jupiter.params.provider.ValueSource; -import server.haengdong.exception.HaengdongException; - -class EventTest { - - @DisplayName("공백 문자가 연속되지 않고, 이름이 2자 이상 20자 이하인 행사를 생성하면 예외가 발생하지 않는다.") - @ParameterizedTest - @ValueSource(strings = {"12", "12345678901234567890", "공 백", " 공백", "공백 ", " 공 백 "}) - void createSuccessTest(String eventName) { - assertThatCode(() -> new Event(eventName, "1234", "TEST_TOKEN")) - .doesNotThrowAnyException(); - } - - @DisplayName("공백 문자가 연속되면 예외가 발생한다.") - @ParameterizedTest - @ValueSource(strings = {" 공백", "공백 ", "공백 연속", "공 백"}) - void createFailTest1(String eventName) { - assertThatCode(() -> new Event(eventName, "1234", "TEST_TOKEN")) - .isInstanceOf(HaengdongException.class) - .hasMessage("행사 이름에는 공백 문자가 연속될 수 없습니다."); - } - - @DisplayName("이름이 1자 미만이거나 20자 초과인 경우 예외가 발생한다.") - @ParameterizedTest - @ValueSource(strings = {"", " ", "123456789012345678901"}) - void createFilTest2(String eventName) { - assertThatCode(() -> new Event(eventName, "1234", "TEST_TOKEN")) - .isInstanceOf(HaengdongException.class) - .hasMessage("행사 이름은 1자 이상 20자 이하만 입력 가능합니다."); - } - - @DisplayName("비밀번호는 4자리 숫자 입니다.") - @ParameterizedTest - @ValueSource(strings = {"1", "12", "123", "12345", "adgd"}) - void validatePassword(String password) { - assertThatCode(() -> new Event("이름", password, "TEST_TOKEN")) - .isInstanceOf(HaengdongException.class); - } - - @DisplayName("비밀번호가 다른지 검증한다.") - @Test - void isNotSamePassword() { - String rawPassword = "1234"; - Event event = new Event("이름", rawPassword, "TEST_TOKEN"); - - assertThat(event.isPasswordMismatch(rawPassword)).isFalse(); - } - - @DisplayName("비밀번호가 다른지 검증한다.") - @Test - void isNotSamePassword1() { - String rawPassword = "1234"; - Event event = new Event("이름", "5678", "TEST_TOKEN"); - - assertThat(event.isPasswordMismatch(rawPassword)).isTrue(); - } - - @DisplayName("이름을 수정한다.") - @Test - void renameTest() { - Event event = new Event("이름", "1234", "TEST_TOKEN"); - - event.rename("새로운 이름"); - - assertThat(event.getName()).isEqualTo("새로운 이름"); - } - - @DisplayName("계좌 정보에 은행 이름과 계좌 번호가 모두 포함된다.") - @Test - void changeAccountTest() { - Event event = new Event("이름", "1234", "TEST_TOKEN"); - - event.changeAccount("토스뱅크", "12345678"); - - assertAll( - () -> assertThat(event.getBankName()).isEqualTo("토스뱅크"), - () -> assertThat(event.getAccountNumber()).isEqualTo("12345678") - ); - } - - @DisplayName("계좌 정보에 은행 이름과 계좌 번호가 모두 포함되지 않으면 예외가 발생한다.") - @Test - void changeAccountTest1() { - Event event = new Event("이름", "1234", "TEST_TOKEN"); - - assertThatThrownBy(() -> event.changeAccount("행대뱅크", "")) - .isInstanceOf(HaengdongException.class); - } - - @DisplayName("지원하는 은행이면 예외가 발생하지 않는다.") - @ParameterizedTest - @ValueSource(strings = {"토스뱅크", "KB국민은행"}) - void changeAccountTest2(String bankName) { - Event event = new Event("이름", "1234", "TEST_TOKEN"); - - assertThatCode(() -> event.changeAccount(bankName, "12345678")) - .doesNotThrowAnyException(); - } - - @DisplayName("지원하지 않는 은행이면 예외가 발생한다.") - @ParameterizedTest - @ValueSource(strings = {"행대뱅크", "토스 뱅크", "망쵸뱅크", "KB 국민은행"}) - void changeAccountTest3(String bankName) { - Event event = new Event("이름", "1234", "TEST_TOKEN"); - - assertThatThrownBy(() -> event.changeAccount(bankName, "12345678")) - .isInstanceOf(HaengdongException.class); - } - - @DisplayName("계좌 번호가 8자 이상 30자 이하면 예외가 발생하지 않는다.") - @ParameterizedTest - @ValueSource(strings = {"12345678", "123456789012345678901234567890"}) - void changeAccountTest4(String accountNumber) { - Event event = new Event("이름", "1234", "TEST_TOKEN"); - - assertThatCode(() -> event.changeAccount("토스뱅크", accountNumber)) - .doesNotThrowAnyException(); - } - - @DisplayName("계좌 번호가 8자 미만 30자 초과면 예외가 발생한다.") - @ParameterizedTest - @ValueSource(strings = {"", " ", "1234567", "1234567890123456789012345678901"}) - void changeAccountTest5(String accountNumber) { - Event event = new Event("이름", "1234", "TEST_TOKEN"); - - assertThatThrownBy(() -> event.changeAccount("토스뱅크", accountNumber)) - .isInstanceOf(HaengdongException.class); - } - - @DisplayName("계좌 정보를 조회한다.") - @Test - void getBankNameTest() { - Event event = new Event("이름", "1234", "TEST_TOKEN"); - - event.changeAccount("토스뱅크", "12345678"); - - assertAll( - () -> assertThat(event.getBankName()).isEqualTo("토스뱅크"), - () -> assertThat(event.getAccountNumber()).isEqualTo("12345678") - ); - } - - @DisplayName("계좌 번호에 공백이 있어도 계좌 정보를 정상적으로 조회한다.") - @Test - void getBankNameTest1() { - Event event = new Event("이름", "1234", "TEST_TOKEN"); - - event.changeAccount("토스뱅크", "1234 5678 9012"); - - assertAll( - () -> assertThat(event.getBankName()).isEqualTo("토스뱅크"), - () -> assertThat(event.getAccountNumber()).isEqualTo("1234 5678 9012") - ); - } -} diff --git a/server/src/test/java/server/haengdong/domain/member/MemberBillReportTest.java b/server/src/test/java/server/haengdong/domain/member/MemberBillReportTest.java deleted file mode 100644 index 187d117f7..000000000 --- a/server/src/test/java/server/haengdong/domain/member/MemberBillReportTest.java +++ /dev/null @@ -1,42 +0,0 @@ -package server.haengdong.domain.member; - -import static org.assertj.core.api.Assertions.assertThat; - -import java.util.List; -import java.util.Map; -import org.junit.jupiter.api.DisplayName; -import org.junit.jupiter.api.Test; -import server.haengdong.domain.bill.Bill; -import server.haengdong.domain.event.Event; -import server.haengdong.domain.bill.MemberBillReport; -import server.haengdong.support.fixture.Fixture; - -class MemberBillReportTest { - - @DisplayName("지출 목록으로 참가자 정산 리포트를 생성한다.") - @Test - void createByBills() { - Event event = Fixture.EVENT1; - Member member1 = new Member(1L, event, "소하", false); - Member member2 = new Member(2L, event, "감자", false); - Member member3 = new Member(3L, event, "쿠키", false); - Member member4 = new Member(4L, event, "고구마", false); - List members = List.of(member1, member2, member3, member4); - List bills = List.of( - Bill.create(event, "뽕족", 60_000L, members), - Bill.create(event, "인생네컷", 20_000L, members) - ); - - MemberBillReport memberBillReport = MemberBillReport.createByBills(bills); - - assertThat(memberBillReport.getReports()) - .containsAllEntriesOf( - Map.of( - member1, 20_000L, - member2, 20_000L, - member3, 20_000L, - member4, 20_000L - ) - ); - } -} diff --git a/server/src/test/java/server/haengdong/domain/member/UpdatedMembersTest.java b/server/src/test/java/server/haengdong/domain/member/UpdatedMembersTest.java deleted file mode 100644 index 9f0338ffb..000000000 --- a/server/src/test/java/server/haengdong/domain/member/UpdatedMembersTest.java +++ /dev/null @@ -1,118 +0,0 @@ -package server.haengdong.domain.member; - -import static org.assertj.core.api.Assertions.assertThat; -import static org.assertj.core.api.Assertions.assertThatCode; -import static org.assertj.core.api.Assertions.assertThatThrownBy; - -import java.util.List; -import org.junit.jupiter.api.DisplayName; -import org.junit.jupiter.api.Test; -import server.haengdong.domain.event.Event; -import server.haengdong.exception.HaengdongException; - -class UpdatedMembersTest { - - @DisplayName("이벤트 이름들은 중복될 수 없다.") - @Test - void validateNameUnique() { - Event event = new Event("행동대장 회식", "1234", "1231415jaksdf"); - List members = List.of( - new Member(1L, event, "고구마", false), - new Member(2L, event, "감자", false), - new Member(3L, event, "감자", false) - ); - - assertThatThrownBy(() -> new UpdatedMembers(members)) - .isInstanceOf(HaengdongException.class) - .hasMessage("중복된 참여 인원 이름 변경 요청이 존재합니다."); - } - - @DisplayName("이벤트 회원들은 중복될 수 없다.") - @Test - void validateMemberUnique() { - Event event = new Event("행동대장 회식", "1234", "1231415jaksdf"); - Member member1 = new Member(1L, event, "고구마", false); - Member member2 = new Member(2L, event, "감자", false); - List members = List.of(member1, member2, member2); - - - assertThatThrownBy(() -> new UpdatedMembers(members)) - .isInstanceOf(HaengdongException.class) - .hasMessage("중복된 참여 인원 이름 변경 요청이 존재합니다."); - } - - @DisplayName("이벤트 이름들로 이벤트 참여자들을 생성한다.") - @Test - void create() { - Event event = new Event("행동대장 회식", "1234", "1231415jaksdf"); - Member member1 = new Member(1L, event, "고구마", false); - Member member2 = new Member(2L, event, "감자", false); - Member member3 = new Member(3L, event, "당근", false); - List members = List.of(member1, member2, member3); - - UpdatedMembers eventUpdatedMembers = new UpdatedMembers(members); - assertThat(eventUpdatedMembers.getMembers()).hasSize(3) - .containsExactlyInAnyOrder(member1, member2, member3); - } - - @DisplayName("이벤트의 참여자들 전체가 존재하지 않으면 업데이트할 수 없다.") - @Test - void validateUpdatedMembersExist() { - Event event = new Event("행동대장 회식", "1234", "1231415jaksdf"); - Member member1 = new Member(1L, event, "고구마", false); - Member member2 = new Member(2L, event, "감자", false); - Member member3 = new Member(3L, event, "당근", false); - Member member4 = new Member(4L, event, "양파", false); - List members = List.of(member1, member2, member3, member4); - - Member updateMember1 = new Member(1L, event, "토다리", false); - Member updateMember2 = new Member(2L, event, "쿠키", false); - Member updateMember3 = new Member(3L, event, "백호", false); - UpdatedMembers updatedMembers = new UpdatedMembers(List.of(updateMember1, updateMember2, updateMember3)); - - assertThatThrownBy(() -> updatedMembers.validateUpdatable(members)) - .isInstanceOf(HaengdongException.class) - .hasMessage("업데이트 요청된 참여자 ID 목록과 기존 행사 참여자 ID 목록이 일치하지 않습니다."); - } - - @DisplayName("업데이트할 이름 중에 기존 이벤트의 참여자들의 이름과 중복되면 업데이트할 수 없다.") - @Test - void validateUpdatedNamesUnique() { - Event event = new Event("행동대장 회식", "1234", "1231415jaksdf"); - Member member1 = new Member(1L, event, "고구마", false); - Member member2 = new Member(2L, event, "감자", false); - Member member3 = new Member(3L, event, "당근", false); - Member member4 = new Member(4L, event, "양파", false); - List members = List.of(member1, member2, member3, member4); - - Member updateMember1 = new Member(1L, event, "토다리", false); - Member updateMember2 = new Member(2L, event, "쿠키", false); - Member updateMember3 = new Member(3L, event, "백호", false); - Member updateMember4 = new Member(4L, event, "감자", false); - UpdatedMembers updatedMembers = new UpdatedMembers(List.of(updateMember1, updateMember2, updateMember3, updateMember4)); - - assertThatThrownBy(() -> updatedMembers.validateUpdatable(members)) - .isInstanceOf(HaengdongException.class) - .hasMessage("행사에 중복된 참여자 이름이 존재합니다."); - } - - @DisplayName("이벤트의 참여자들 전체를 업데이트 검증한다.") - @Test - void validateUpdatable() { - Event event = new Event("행동대장 회식", "1234", "1231415jaksdf"); - Member member1 = new Member(1L, event, "고구마", false); - Member member2 = new Member(2L, event, "감자", false); - Member member3 = new Member(3L, event, "당근", false); - Member member4 = new Member(4L, event, "양파", false); - List members = List.of(member1, member2, member3, member4); - - Member updateMember1 = new Member(1L, event, "토다리", false); - Member updateMember2 = new Member(2L, event, "쿠키", false); - Member updateMember3 = new Member(3L, event, "백호", false); - Member updateMember4 = new Member(4L, event, "망쵸", false); - UpdatedMembers updatedMembers = new UpdatedMembers(List.of(updateMember1, updateMember2, updateMember3, updateMember4)); - - assertThatCode(() -> updatedMembers.validateUpdatable(members)) - .doesNotThrowAnyException(); - } -} diff --git a/server/src/test/java/server/haengdong/domain/step/StepTest.java b/server/src/test/java/server/haengdong/domain/step/StepTest.java deleted file mode 100644 index 5c5631840..000000000 --- a/server/src/test/java/server/haengdong/domain/step/StepTest.java +++ /dev/null @@ -1,50 +0,0 @@ -package server.haengdong.domain.step; - -import static org.assertj.core.api.Assertions.assertThat; -import static org.assertj.core.api.Assertions.assertThatThrownBy; -import static server.haengdong.support.fixture.Fixture.EVENT1; - -import java.util.List; -import org.junit.jupiter.api.DisplayName; -import org.junit.jupiter.api.Test; -import server.haengdong.domain.bill.Bill; -import server.haengdong.domain.member.Member; -import server.haengdong.exception.HaengdongException; - -class StepTest { - - @DisplayName("회원 구성이 같은 지출은 Step에 추가될 수 있다.") - @Test - void add1() { - Member member1 = new Member(1L, EVENT1, "감자", false); - Member member2 = new Member(2L, EVENT1, "고구마", false); - Member member3 = new Member(3L, EVENT1, "당근", false); - Member member4 = new Member(4L, EVENT1, "양파", false); - Bill bill1 = Bill.create(EVENT1, "뽕족", 10_000L, List.of(member1, member2, member3, member4)); - Step step = Step.of(bill1); - - Bill bill2 = Bill.create(EVENT1, "인생네컷", 5_000L, List.of(member2, member3, member1, member4)); - - step.add(bill2); - - List bills = step.getBills(); - - assertThat(bills).hasSize(2); - } - - @DisplayName("회원 구성이 댜른 지출은 Step에 추가될 수 없다.") - @Test - void add2() { - Member member1 = new Member(1L, EVENT1, "감자", false); - Member member2 = new Member(2L, EVENT1, "고구마", false); - Member member3 = new Member(3L, EVENT1, "당근", false); - Member member4 = new Member(4L, EVENT1, "양파", false); - Bill bill1 = Bill.create(EVENT1, "뽕족", 10_000L, List.of(member1, member2, member3, member4)); - Step step = Step.of(bill1); - - Bill bill2 = Bill.create(EVENT1, "인생네컷", 5_000L, List.of(member2, member3, member1)); - - assertThatThrownBy(() -> step.add(bill2)) - .isInstanceOf(HaengdongException.class); - } -} diff --git a/server/src/test/java/server/haengdong/presentation/MemberControllerTest.java b/server/src/test/java/server/haengdong/presentation/MemberControllerTest.java deleted file mode 100644 index ff824831b..000000000 --- a/server/src/test/java/server/haengdong/presentation/MemberControllerTest.java +++ /dev/null @@ -1,77 +0,0 @@ -package server.haengdong.presentation; - -import static org.mockito.ArgumentMatchers.any; -import static org.mockito.ArgumentMatchers.anyString; -import static org.mockito.BDDMockito.given; -import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get; -import static org.springframework.test.web.servlet.result.MockMvcResultHandlers.print; -import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.jsonPath; -import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; -import static server.haengdong.support.fixture.Fixture.MEMBER1; -import static server.haengdong.support.fixture.Fixture.MEMBER2; -import static server.haengdong.support.fixture.Fixture.MEMBER3; - -import java.util.List; -import org.junit.jupiter.api.DisplayName; -import org.junit.jupiter.api.Test; -import org.springframework.http.MediaType; -import server.haengdong.application.response.MemberAppResponse; -import server.haengdong.application.response.MemberDepositAppResponse; -import server.haengdong.application.response.MembersDepositAppResponse; -import server.haengdong.domain.member.Member; - -class MemberControllerTest extends ControllerTestSupport { - - @DisplayName("행사에 참여한 전체 인원을 조회한다.") - @Test - void findAllMembersTest() throws Exception { - Member member1 = MEMBER1; - Member member2 = MEMBER2; - Member member3 = MEMBER3; - List members = List.of( - MemberDepositAppResponse.of(member1), - MemberDepositAppResponse.of(member2), - MemberDepositAppResponse.of(member3) - ); - - MembersDepositAppResponse memberAppResponse = new MembersDepositAppResponse(members); - given(memberService.findAllMembers(anyString())).willReturn(memberAppResponse); - - mockMvc.perform(get("/api/events/{eventId}/members", "TOKEN")) - .andDo(print()) - .andExpect(status().isOk()) - .andExpect(jsonPath("$.members").isArray()) - .andExpect(jsonPath("$.members[0].id").value(member1.getId())) - .andExpect(jsonPath("$.members[0].name").value(member1.getName())) - .andExpect(jsonPath("$.members[0].isDeposited").value(member1.isDeposited())) - .andExpect(jsonPath("$.members[1].id").value(member2.getId())) - .andExpect(jsonPath("$.members[1].name").value(member2.getName())) - .andExpect(jsonPath("$.members[1].isDeposited").value(member2.isDeposited())) - .andExpect(jsonPath("$.members[2].id").value(member3.getId())) - .andExpect(jsonPath("$.members[2].name").value(member3.getName())) - .andExpect(jsonPath("$.members[2].isDeposited").value(member3.isDeposited())); - } - - @DisplayName("현재 참여 인원을 조회합니다.") - @Test - void getCurrentMembers() throws Exception { - Member member1 = MEMBER1; - Member member2 = MEMBER2; - List members = List.of( - MemberAppResponse.of(member1), - MemberAppResponse.of(member2) - ); - - given(memberService.getCurrentMembers(any())).willReturn(members); - - mockMvc.perform(get("/api/events/{eventId}/members/current", "TOKEN") - .accept(MediaType.APPLICATION_JSON)) - .andDo(print()) - .andExpect(status().isOk()) - .andExpect(jsonPath("$.members").isArray()) - .andExpect(jsonPath("$.members[0].id").value(member1.getId())) - .andExpect(jsonPath("$.members[0].name").value(member1.getName())) - .andExpect(jsonPath("$.members[1].id").value(member2.getId())) - .andExpect(jsonPath("$.members[1].name").value(member2.getName())); - } -} diff --git a/server/src/test/java/server/haengdong/support/fixture/Fixture.java b/server/src/test/java/server/haengdong/support/fixture/Fixture.java deleted file mode 100644 index e05b43c23..000000000 --- a/server/src/test/java/server/haengdong/support/fixture/Fixture.java +++ /dev/null @@ -1,18 +0,0 @@ -package server.haengdong.support.fixture; - -import jakarta.servlet.http.Cookie; -import server.haengdong.domain.bill.Bill; -import server.haengdong.domain.member.Member; -import server.haengdong.domain.event.Event; - -public class Fixture { - - public static final Event EVENT1 = new Event("쿠키", "1234", "TOKEN1"); - public static final Event EVENT2 = new Event("웨디", "1234", "TOKEN2"); - public static final Cookie EVENT_COOKIE = new Cookie("eventToken", "토큰토큰"); - public static final Member MEMBER1 = new Member(EVENT1, "토다리"); - public static final Member MEMBER2 = new Member(EVENT1, "쿠키"); - public static final Member MEMBER3 = new Member(EVENT1, "소하"); - public static final Bill BILL1 = new Bill(EVENT1, "행동대장 회식", 10000L); - public static final Bill BILL2 = new Bill(EVENT2, "행동대장 회식2", 20000L); -}