diff --git a/docker-compose.yml b/docker-compose.yml new file mode 100644 index 00000000..b58bbf39 --- /dev/null +++ b/docker-compose.yml @@ -0,0 +1,28 @@ +version: '3' + +services: + + mysql: + image: mysql/mysql-server:5.7 + environment: + MYSQL_ROOT_HOST: '%' + MYSQL_USER: "hous" + MYSQL_PASSWORD: "hous" + MYSQL_DATABASE: "hous" + ports: + - "3306:3306" + command: + - "mysqld" + - "--character-set-server=utf8mb4" + - "--collation-server=utf8mb4_unicode_ci" + + redis: + image: redis:alpine + command: redis-server --port 6379 + container_name: redis_boot + hostname: redis_boot + labels: + - "name=redis" + - "mode=standalone" + ports: + - 6379:6379 diff --git a/src/main/java/hous/server/ServerApplication.java b/src/main/java/hous/server/ServerApplication.java index 724e1e32..dcce36c3 100644 --- a/src/main/java/hous/server/ServerApplication.java +++ b/src/main/java/hous/server/ServerApplication.java @@ -3,6 +3,7 @@ import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.cloud.openfeign.EnableFeignClients; +import org.springframework.context.annotation.EnableAspectJAutoProxy; import org.springframework.data.jpa.repository.config.EnableJpaAuditing; import org.springframework.scheduling.annotation.EnableScheduling; import springfox.documentation.swagger2.annotations.EnableSwagger2; @@ -10,6 +11,7 @@ @EnableScheduling @EnableFeignClients @EnableJpaAuditing +@EnableAspectJAutoProxy @SpringBootApplication @EnableSwagger2 public class ServerApplication { diff --git a/src/main/java/hous/server/common/aspect/PreventDuplicateRequest.java b/src/main/java/hous/server/common/aspect/duplicate/PreventDuplicateRequest.java similarity index 85% rename from src/main/java/hous/server/common/aspect/PreventDuplicateRequest.java rename to src/main/java/hous/server/common/aspect/duplicate/PreventDuplicateRequest.java index 5a71243a..56fec5a8 100644 --- a/src/main/java/hous/server/common/aspect/PreventDuplicateRequest.java +++ b/src/main/java/hous/server/common/aspect/duplicate/PreventDuplicateRequest.java @@ -1,4 +1,4 @@ -package hous.server.common.aspect; +package hous.server.common.aspect.duplicate; import java.lang.annotation.ElementType; import java.lang.annotation.Retention; diff --git a/src/main/java/hous/server/common/aspect/RequestAspect.java b/src/main/java/hous/server/common/aspect/duplicate/RequestAspect.java similarity index 86% rename from src/main/java/hous/server/common/aspect/RequestAspect.java rename to src/main/java/hous/server/common/aspect/duplicate/RequestAspect.java index 7a667c3b..e3b7ccbd 100644 --- a/src/main/java/hous/server/common/aspect/RequestAspect.java +++ b/src/main/java/hous/server/common/aspect/duplicate/RequestAspect.java @@ -1,4 +1,4 @@ -package hous.server.common.aspect; +package hous.server.common.aspect.duplicate; import hous.server.common.exception.ConflictException; import hous.server.domain.common.RedisKey; @@ -19,7 +19,7 @@ public class RequestAspect { private final RedisTemplate redisTemplate; - @Before("@annotation(hous.server.common.aspect.PreventDuplicateRequest)") + @Before("@annotation(hous.server.common.aspect.duplicate.PreventDuplicateRequest)") public void beforeRequest(final JoinPoint joinPoint) { Long userId = (Long) joinPoint.getArgs()[0]; if (redisTemplate.opsForValue().get(RedisKey.DUPLICATE_REQUEST + userId) != null) { @@ -29,7 +29,7 @@ public void beforeRequest(final JoinPoint joinPoint) { redisTemplate.opsForValue().set(RedisKey.DUPLICATE_REQUEST + userId, Long.toString(userId)); } - @After("@annotation(hous.server.common.aspect.PreventDuplicateRequest)") + @After("@annotation(hous.server.common.aspect.duplicate.PreventDuplicateRequest)") public void afterReturningRequest(final JoinPoint joinPoint) { Long userId = (Long) joinPoint.getArgs()[0]; redisTemplate.opsForValue().getAndDelete(RedisKey.DUPLICATE_REQUEST + userId); diff --git a/src/main/java/hous/server/common/aspect/logging/LoggingAspect.java b/src/main/java/hous/server/common/aspect/logging/LoggingAspect.java new file mode 100644 index 00000000..000eebf4 --- /dev/null +++ b/src/main/java/hous/server/common/aspect/logging/LoggingAspect.java @@ -0,0 +1,56 @@ +package hous.server.common.aspect.logging; + +import lombok.extern.slf4j.Slf4j; +import org.aspectj.lang.ProceedingJoinPoint; +import org.aspectj.lang.annotation.Around; +import org.aspectj.lang.annotation.Aspect; +import org.aspectj.lang.annotation.Pointcut; +import org.springframework.stereotype.Component; +import org.springframework.web.context.request.RequestContextHolder; +import org.springframework.web.context.request.ServletRequestAttributes; + +import javax.servlet.http.HttpServletRequest; +import java.util.Enumeration; +import java.util.HashMap; +import java.util.Map; + +@Aspect +@Component +@Slf4j +public class LoggingAspect { + + /** + * execution([수식어] 리턴타입 [클래스이름].이름(파라미터) + * * : 모든 값 포함 + * .. : 0개 이상 의미 + *

+ * hous.server.controller 패키지 내부의 모든 클래스에서 파라미터가 0개 이상인 모든 메서드 + */ + @Pointcut("execution(* hous.server.controller..*(..))") + public void controllerExecute() { + } + + @Around("hous.server.common.aspect.logging.LoggingAspect.controllerExecute()") + public Object requestLogging(ProceedingJoinPoint proceedingJoinPoint) throws Throwable { + HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.currentRequestAttributes()).getRequest(); + long startAt = System.currentTimeMillis(); + Object returnValue = proceedingJoinPoint.proceed(proceedingJoinPoint.getArgs()); + long endAt = System.currentTimeMillis(); + log.info("====> Request: {} {} ({}ms)\n *Header = {}\n", request.getMethod(), request.getRequestURL(), endAt - startAt, getHeaders(request)); + if (returnValue != null) { + log.info("====> Response: {}", returnValue); + } + return returnValue; + } + + private Map getHeaders(HttpServletRequest request) { + Map headerMap = new HashMap<>(); + + Enumeration headerArray = request.getHeaderNames(); + while (headerArray.hasMoreElements()) { + String headerName = headerArray.nextElement(); + headerMap.put(headerName, request.getHeader(headerName)); + } + return headerMap; + } +} diff --git a/src/main/java/hous/server/controller/auth/AuthController.java b/src/main/java/hous/server/controller/auth/AuthController.java index 362c9c86..5fc6d139 100644 --- a/src/main/java/hous/server/controller/auth/AuthController.java +++ b/src/main/java/hous/server/controller/auth/AuthController.java @@ -1,6 +1,6 @@ package hous.server.controller.auth; -import hous.server.common.aspect.PreventDuplicateRequest; +import hous.server.common.aspect.duplicate.PreventDuplicateRequest; import hous.server.common.dto.ErrorResponse; import hous.server.common.dto.SuccessResponse; import hous.server.common.success.SuccessCode; diff --git a/src/main/java/hous/server/controller/room/RoomController.java b/src/main/java/hous/server/controller/room/RoomController.java index 2f730949..4fe8e642 100644 --- a/src/main/java/hous/server/controller/room/RoomController.java +++ b/src/main/java/hous/server/controller/room/RoomController.java @@ -1,6 +1,6 @@ package hous.server.controller.room; -import hous.server.common.aspect.PreventDuplicateRequest; +import hous.server.common.aspect.duplicate.PreventDuplicateRequest; import hous.server.common.dto.ErrorResponse; import hous.server.common.dto.SuccessResponse; import hous.server.common.success.SuccessCode; diff --git a/src/main/java/hous/server/controller/rule/RuleController.java b/src/main/java/hous/server/controller/rule/RuleController.java index 8e6cf322..9387bdf5 100644 --- a/src/main/java/hous/server/controller/rule/RuleController.java +++ b/src/main/java/hous/server/controller/rule/RuleController.java @@ -1,6 +1,6 @@ package hous.server.controller.rule; -import hous.server.common.aspect.PreventDuplicateRequest; +import hous.server.common.aspect.duplicate.PreventDuplicateRequest; import hous.server.common.dto.ErrorResponse; import hous.server.common.dto.SuccessResponse; import hous.server.config.interceptor.auth.Auth; diff --git a/src/main/java/hous/server/controller/todo/TodoController.java b/src/main/java/hous/server/controller/todo/TodoController.java index f548d6f4..5d345ae7 100644 --- a/src/main/java/hous/server/controller/todo/TodoController.java +++ b/src/main/java/hous/server/controller/todo/TodoController.java @@ -1,6 +1,6 @@ package hous.server.controller.todo; -import hous.server.common.aspect.PreventDuplicateRequest; +import hous.server.common.aspect.duplicate.PreventDuplicateRequest; import hous.server.common.dto.ErrorResponse; import hous.server.common.dto.SuccessResponse; import hous.server.config.interceptor.auth.Auth; diff --git a/src/main/java/hous/server/controller/user/UserController.java b/src/main/java/hous/server/controller/user/UserController.java index 1e3ae36b..808f77f7 100644 --- a/src/main/java/hous/server/controller/user/UserController.java +++ b/src/main/java/hous/server/controller/user/UserController.java @@ -1,6 +1,6 @@ package hous.server.controller.user; -import hous.server.common.aspect.PreventDuplicateRequest; +import hous.server.common.aspect.duplicate.PreventDuplicateRequest; import hous.server.common.dto.ErrorResponse; import hous.server.common.dto.SuccessResponse; import hous.server.common.success.SuccessCode; diff --git a/src/main/java/hous/server/domain/room/Room.java b/src/main/java/hous/server/domain/room/Room.java index 3a0e18e8..d35ddeb5 100644 --- a/src/main/java/hous/server/domain/room/Room.java +++ b/src/main/java/hous/server/domain/room/Room.java @@ -34,12 +34,6 @@ public class Room extends AuditingTimeEntity { @Column(nullable = false) private int participantsCnt; - @Column(nullable = false) - private int rulesCnt; - - @Column(nullable = false) - private int todosCnt; - @OneToMany(mappedBy = "room", fetch = FetchType.LAZY, cascade = CascadeType.ALL, orphanRemoval = true) private final List participates = new ArrayList<>(); @@ -55,8 +49,6 @@ public static Room newInstance(Onboarding owner, String name, String code) { .name(name) .code(code) .participantsCnt(0) - .rulesCnt(0) - .todosCnt(0) .build(); } @@ -80,7 +72,6 @@ public void deleteParticipate(Participate participate) { public void addRules(List rules) { this.rules.addAll(rules); - this.rulesCnt += rules.size(); } public void updateRule(Rule rule) { @@ -89,12 +80,10 @@ public void updateRule(Rule rule) { public void deleteRule(Rule rule) { this.rules.remove(rule); - this.rulesCnt -= 1; } public void addTodo(Todo todo) { this.todos.add(todo); - this.todosCnt += 1; } public void updateTodo(Todo todo) { @@ -103,6 +92,5 @@ public void updateTodo(Todo todo) { public void deleteTodo(Todo todo) { this.todos.remove(todo); - this.todosCnt -= 1; } } diff --git a/src/main/java/hous/server/service/room/dto/request/SetRoomNameRequestDto.java b/src/main/java/hous/server/service/room/dto/request/SetRoomNameRequestDto.java index ffa13560..b6c41d4c 100644 --- a/src/main/java/hous/server/service/room/dto/request/SetRoomNameRequestDto.java +++ b/src/main/java/hous/server/service/room/dto/request/SetRoomNameRequestDto.java @@ -2,10 +2,7 @@ import hous.server.domain.common.Constraint; import io.swagger.annotations.ApiModelProperty; -import lombok.AccessLevel; -import lombok.Getter; -import lombok.NoArgsConstructor; -import lombok.ToString; +import lombok.*; import javax.validation.constraints.NotBlank; import javax.validation.constraints.Size; @@ -13,10 +10,18 @@ @ToString @Getter @NoArgsConstructor(access = AccessLevel.PRIVATE) +@AllArgsConstructor(access = AccessLevel.PRIVATE) +@Builder(access = AccessLevel.PRIVATE) public class SetRoomNameRequestDto { @ApiModelProperty(value = "방 이름", example = "러블리더블리") @NotBlank(message = "{room.name.notBlank}") @Size(max = Constraint.ROOM_NAME_MAX, message = "{room.name.max}") private String name; + + public static SetRoomNameRequestDto of(String name) { + return SetRoomNameRequestDto.builder() + .name(name) + .build(); + } } diff --git a/src/main/java/hous/server/service/rule/RuleService.java b/src/main/java/hous/server/service/rule/RuleService.java index b5abca13..1e2d1621 100644 --- a/src/main/java/hous/server/service/rule/RuleService.java +++ b/src/main/java/hous/server/service/rule/RuleService.java @@ -17,6 +17,7 @@ import hous.server.service.rule.dto.request.CreateRuleRequestDto; import hous.server.service.rule.dto.request.DeleteRuleReqeustDto; import hous.server.service.rule.dto.request.UpdateRuleRequestDto; +import hous.server.service.rule.dto.response.RuleInfo; import hous.server.service.user.UserServiceUtils; import lombok.RequiredArgsConstructor; import org.springframework.data.redis.core.RedisTemplate; @@ -47,7 +48,7 @@ public void createRule(CreateRuleRequestDto request, Long userId) { Onboarding me = user.getOnboarding(); Room room = RoomServiceUtils.findParticipatingRoom(user); RuleServiceUtils.validateRuleCounts(room, request.getRuleNames().size()); -// RuleServiceUtils.existsRuleByRoomRules(room, request.getRuleNames()); //TODO 다음 릴리즈 때 클라에서 추가할 예정이라 우선 주석 처리 + RuleServiceUtils.existsRuleByRoomRules(room, request.getRuleNames()); AtomicInteger ruleIdx = new AtomicInteger(RuleServiceUtils.findRuleIdxByRoomId(ruleRepository, room)); List rules = request.getRuleNames().stream() .map(ruleName -> { @@ -77,7 +78,7 @@ public void createRule(CreateRuleRequestDto request, Long userId) { public void updateRules(UpdateRuleRequestDto request, Long userId) { User user = UserServiceUtils.findUserById(userRepository, userId); Room room = RoomServiceUtils.findParticipatingRoom(user); -// RuleServiceUtils.existsRuleByRoomRules(room, request.getRules().stream().map(RuleInfo::getName).collect(Collectors.toList())); //TODO 다음 릴리즈 때 클라에서 추가할 예정이라 우선 주석 처리 + RuleServiceUtils.existsRuleByRules(request.getRules().stream().map(RuleInfo::getName).collect(Collectors.toList())); for (int idx = 0; idx < request.getRules().size(); idx++) { Rule rule = RuleServiceUtils.findRuleByIdAndRoom(ruleRepository, request.getRules().get(idx).getId(), room); RuleServiceUtils.validateRuleName(room, request.getRules().get(idx).getName()); diff --git a/src/main/java/hous/server/service/rule/RuleServiceUtils.java b/src/main/java/hous/server/service/rule/RuleServiceUtils.java index aebc732e..8efba2c0 100644 --- a/src/main/java/hous/server/service/rule/RuleServiceUtils.java +++ b/src/main/java/hous/server/service/rule/RuleServiceUtils.java @@ -11,6 +11,7 @@ import lombok.AccessLevel; import lombok.NoArgsConstructor; +import java.util.HashSet; import java.util.List; import java.util.stream.Collectors; @@ -36,7 +37,7 @@ public static void validateRuleName(Room room, String ruleName) { } public static void validateRuleCounts(Room room, int requestRuleCnt) { - if (room.getRulesCnt() + requestRuleCnt > Constraint.RULE_COUNT_MAX) { + if (room.getRules().size() + requestRuleCnt > Constraint.RULE_COUNT_MAX) { throw new ForbiddenException(String.format("방 (%s) 의 rule 는 30 개를 초과할 수 없습니다.", room.getId()), FORBIDDEN_RULE_COUNT_EXCEPTION); } } @@ -53,8 +54,15 @@ public static void existsRuleByRoomRules(Room room, List requestRules) { List rules = room.getRules().stream().map(Rule::getName).collect(Collectors.toList()); for (String ruleName : requestRules) { if (rules.contains(ruleName)) { - throw new ConflictException(String.format("방 (%s) 에 이미 존재하는 todo (%s) 입니다.", room.getId(), ruleName), CONFLICT_RULE_EXCEPTION); + throw new ConflictException(String.format("방 (%s) 에 이미 존재하는 ruleName (%s) 입니다.", room.getId(), ruleName), CONFLICT_RULE_EXCEPTION); + } } } + + public static void existsRuleByRules(List requestRules) { + if (requestRules.size() != new HashSet<>(requestRules).size()) { + throw new ConflictException("규칙 이름 중복입니다.", CONFLICT_RULE_EXCEPTION); + } + } } diff --git a/src/main/java/hous/server/service/rule/dto/request/CreateRuleRequestDto.java b/src/main/java/hous/server/service/rule/dto/request/CreateRuleRequestDto.java index 2714f71d..0d6665f0 100644 --- a/src/main/java/hous/server/service/rule/dto/request/CreateRuleRequestDto.java +++ b/src/main/java/hous/server/service/rule/dto/request/CreateRuleRequestDto.java @@ -2,10 +2,7 @@ import hous.server.domain.common.Constraint; import io.swagger.annotations.ApiModelProperty; -import lombok.AccessLevel; -import lombok.Getter; -import lombok.NoArgsConstructor; -import lombok.ToString; +import lombok.*; import javax.validation.constraints.NotNull; import javax.validation.constraints.Size; @@ -14,10 +11,18 @@ @ToString @Getter @NoArgsConstructor(access = AccessLevel.PRIVATE) +@AllArgsConstructor(access = AccessLevel.PRIVATE) +@Builder(access = AccessLevel.PRIVATE) public class CreateRuleRequestDto { @ApiModelProperty(value = "규칙 내용 배열", example = "[\"우리집 대장은 김또순\", \"우리집 대장은 혜조니\", \"우리집 대장은 혁주니\", ...]") @NotNull(message = "{rule.list.notNull}") @Size(min = Constraint.RULE_LIST_MIN, message = "{rule.list.min}") private List ruleNames; + + public static CreateRuleRequestDto of(List ruleNames) { + return CreateRuleRequestDto.builder() + .ruleNames(ruleNames) + .build(); + } } diff --git a/src/main/java/hous/server/service/rule/dto/request/DeleteRuleReqeustDto.java b/src/main/java/hous/server/service/rule/dto/request/DeleteRuleReqeustDto.java index 78e6bf3d..209ae6da 100644 --- a/src/main/java/hous/server/service/rule/dto/request/DeleteRuleReqeustDto.java +++ b/src/main/java/hous/server/service/rule/dto/request/DeleteRuleReqeustDto.java @@ -2,10 +2,7 @@ import hous.server.domain.common.Constraint; import io.swagger.annotations.ApiModelProperty; -import lombok.AccessLevel; -import lombok.Getter; -import lombok.NoArgsConstructor; -import lombok.ToString; +import lombok.*; import javax.validation.constraints.NotNull; import javax.validation.constraints.Size; @@ -14,10 +11,18 @@ @ToString @Getter @NoArgsConstructor(access = AccessLevel.PRIVATE) +@AllArgsConstructor(access = AccessLevel.PRIVATE) +@Builder(access = AccessLevel.PRIVATE) public class DeleteRuleReqeustDto { @ApiModelProperty(value = "규칙 id 배열", example = "[12, 13, 14, ...]") @NotNull(message = "{rule.list.notNull}") @Size(min = Constraint.RULE_LIST_MIN, message = "{rule.list.min}") private List rulesIdList; + + public static DeleteRuleReqeustDto of(List rulesIdList) { + return DeleteRuleReqeustDto.builder() + .rulesIdList(rulesIdList) + .build(); + } } diff --git a/src/main/java/hous/server/service/todo/TodoRetrieveService.java b/src/main/java/hous/server/service/todo/TodoRetrieveService.java index 06ff4f97..bf60ed28 100644 --- a/src/main/java/hous/server/service/todo/TodoRetrieveService.java +++ b/src/main/java/hous/server/service/todo/TodoRetrieveService.java @@ -128,7 +128,7 @@ public TodoAllDayResponse getTodoAllDayInfo(Long userId) { .collect(Collectors.toList()); allDayTodosList.add(TodoAllDayInfo.of(dayOfWeek, todoInfos, ourTodoInfos)); } - return TodoAllDayResponse.of(room.getTodosCnt(), allDayTodosList); + return TodoAllDayResponse.of(room.getTodos().size(), allDayTodosList); } public TodoAllMemberResponse getTodoAllMemberInfo(Long userId) { @@ -169,7 +169,7 @@ public TodoAllMemberResponse getTodoAllMemberInfo(Long userId) { }); allMemberTodos.addAll(otherMemberTodos); - return TodoAllMemberResponse.of(room.getTodosCnt(), allMemberTodos); + return TodoAllMemberResponse.of(room.getTodos().size(), allMemberTodos); } public MyTodoInfoResponse getMyTodoInfo(Long userId) { diff --git a/src/main/java/hous/server/service/todo/TodoServiceUtils.java b/src/main/java/hous/server/service/todo/TodoServiceUtils.java index 00a5d72b..2854ee82 100644 --- a/src/main/java/hous/server/service/todo/TodoServiceUtils.java +++ b/src/main/java/hous/server/service/todo/TodoServiceUtils.java @@ -35,7 +35,7 @@ public static Todo findTodoById(TodoRepository todoRepository, Long todoId) { } public static void validateTodoCounts(Room room) { - if (room.getTodosCnt() >= Constraint.TODO_COUNT_MAX) { + if (room.getTodos().size() >= Constraint.TODO_COUNT_MAX) { throw new ForbiddenException(String.format("방 (%s) 의 todo 는 60개를 초과할 수 없습니다.", room.getId()), FORBIDDEN_TODO_COUNT_EXCEPTION); } } diff --git a/src/main/java/hous/server/service/todo/dto/request/TodoInfoRequestDto.java b/src/main/java/hous/server/service/todo/dto/request/TodoInfoRequestDto.java index b7c34902..1e8f9c21 100644 --- a/src/main/java/hous/server/service/todo/dto/request/TodoInfoRequestDto.java +++ b/src/main/java/hous/server/service/todo/dto/request/TodoInfoRequestDto.java @@ -4,10 +4,7 @@ import hous.server.domain.common.Constraint; import hous.server.domain.todo.DayOfWeek; import io.swagger.annotations.ApiModelProperty; -import lombok.AccessLevel; -import lombok.Getter; -import lombok.NoArgsConstructor; -import lombok.ToString; +import lombok.*; import javax.validation.Valid; import javax.validation.constraints.NotBlank; @@ -19,6 +16,8 @@ @ToString @Getter @NoArgsConstructor(access = AccessLevel.PRIVATE) +@AllArgsConstructor(access = AccessLevel.PRIVATE) +@Builder(access = AccessLevel.PRIVATE) public class TodoInfoRequestDto { @ApiModelProperty(value = "todo 이름", example = "청소기 돌리기") @@ -37,6 +36,8 @@ public class TodoInfoRequestDto { @ToString @Getter @NoArgsConstructor(access = AccessLevel.PRIVATE) + @AllArgsConstructor(access = AccessLevel.PRIVATE) + @Builder public static class TodoUser { @ApiModelProperty(value = "담당자 id", example = "1") @@ -51,4 +52,12 @@ public static class TodoUser { public Boolean isPushNotification() { return isPushNotification; } + + public static TodoInfoRequestDto of(String name, Boolean isPushNotification, List todoUsers) { + return TodoInfoRequestDto.builder() + .name(name) + .isPushNotification(isPushNotification) + .todoUsers(todoUsers) + .build(); + } } diff --git a/src/main/java/hous/server/service/user/dto/request/DeleteUserRequestDto.java b/src/main/java/hous/server/service/user/dto/request/DeleteUserRequestDto.java index 75e0b402..e555908b 100644 --- a/src/main/java/hous/server/service/user/dto/request/DeleteUserRequestDto.java +++ b/src/main/java/hous/server/service/user/dto/request/DeleteUserRequestDto.java @@ -12,6 +12,7 @@ @Getter @NoArgsConstructor(access = AccessLevel.PRIVATE) @AllArgsConstructor(access = AccessLevel.PRIVATE) +@Builder(access = AccessLevel.PRIVATE) public class DeleteUserRequestDto { @ApiModelProperty(value = "사유", example = "DONE_LIVING_TOGETHER") @@ -22,4 +23,11 @@ public class DeleteUserRequestDto { @Size(max = Constraint.FEEDBACK_COMMENT_MAX, message = "{user.comment.max}") @NotNull(message = "{user.comment.notNull}") private String comment; + + public static DeleteUserRequestDto of(FeedbackType feedbackType, String comment) { + return DeleteUserRequestDto.builder() + .feedbackType(feedbackType) + .comment(comment) + .build(); + } } diff --git a/src/main/resources/sql/data.sql b/src/main/resources/sql/data.sql new file mode 100644 index 00000000..693ea615 --- /dev/null +++ b/src/main/resources/sql/data.sql @@ -0,0 +1,126 @@ +INSERT INTO personality +(created_at, updated_at, bad_personality_image_url, bad_personality_name, color, description, + good_personality_image_url, good_personality_name, image_url, name, recommend_title, recommend_todo, title) +VALUES ("2022-01-01", "2022-01-01", "bad_personality_image_url", "bad_personality_name", "GRAY", "description", + "good_personality_image_url", "good_personality_name", "image_url", "name", "recommend_title", "recommend_todo", + "title"), + ("2022-01-01", "2022-01-01", "https://team-hous.s3.ap-northeast-2.amazonaws.com/personality/green.png", + "룰 세터 육각이", "YELLOW", + "민감하게 생각하는 생활 영역이 거의 없어\n동글동글하게 공동생활에 쉽게 적응할 수 있어요.\n동글이님과 함께 생활하는 룸메이트를 위한 Tip!\n배려가 필요한 영역이 있다면 동글이 호미와\n직접 얘기해 보는 건 어떤가요?", + "https://team-hous.s3.ap-northeast-2.amazonaws.com/personality/red.png", "슈퍼 팔로워 셋돌이", + "https://team-hous.s3.ap-northeast-2.amazonaws.com/personality/yellow.png", "늘 행복한 동글이", "동글이가 만들면 좋은 Rules", + "모두가 함께하는 대청소의 날 정하기!\n외출 시 가스벨브, 전등 확인하기!", "어떤 상황에서도 Happy~"), + ("2022-01-01", "2022-01-01", "https://team-hous.s3.ap-northeast-2.amazonaws.com/personality/green.png", + "룰 세터 육각이", "RED", + "크게 민감한 생활 영역 없이 유연한 셋돌이!\n독립적이고 적응력이 높아 공동생활에 딱 적합해요.\n셋돌이님과 함께 생활하는 룸메이트를 위한 Tip!\n셋돌이 호미가 바빠서 까먹고 있던 우리 집\nRules나 to do를 알려주는 건 어떤가요?", + "https://team-hous.s3.ap-northeast-2.amazonaws.com/personality/blue.png", "룸메 맞춤형 네각이", + "https://team-hous.s3.ap-northeast-2.amazonaws.com/personality/red.png", "슈퍼 팔로워 셋돌이", "셋돌이가 만들면 좋은 Rules", + "미사용 전자제품 코드는 꼭 뽑아두기!\n외출 시 문 잠금 확인하기!", "오히려 좋아~ 가보자고!"), + ("2022-01-01", "2022-01-01", "https://team-hous.s3.ap-northeast-2.amazonaws.com/personality/yellow.png", + "늘 행복한 동글이", "BLUE", + "높지도 낮지도 않은 딱 좋은\n평균적인 민감도를 가지고 있어요.\n네각이님과 함께 생활하는 룸메이트를 위한 Tip!\n네각이의 생활 성향 그래프를 보고 특정한\n영역에 민감도가 쏠려있다면 살짝 배려해 보아요~", + "https://team-hous.s3.ap-northeast-2.amazonaws.com/personality/purple.png", "하이레벨 오돌이", + "https://team-hous.s3.ap-northeast-2.amazonaws.com/personality/blue.png", "룸메 맞춤형 네각이", "네각이가 만들면 좋은 Rules", + "밥 먹고 설거지는 바로 하기!\n소등 시간 이후에는 조용히 하기!", "모두모두 내게 모여라!"), + ("2022-01-01", "2022-01-01", "https://team-hous.s3.ap-northeast-2.amazonaws.com/personality/yellow.png", + "늘 행복한 동글이", "PURPLE", + "여러 생활 영역에 대해 존중의 기준이 대체로 높아\n다른 룸메이트의 민감한 부분과 무심한 부분\n모두를 충분히 공감하고 이해할 수 있어요.\n오돌이님과 함께 생활하는 룸메이트를 위한 Tip!\n말하기 어려운 게 있는지 슬쩍 물어보면 아주 센스쟁이!", + "https://team-hous.s3.ap-northeast-2.amazonaws.com/personality/green.png", "룰 세터 육각이", + "https://team-hous.s3.ap-northeast-2.amazonaws.com/personality/purple.png", "하이레벨 오돌이", "오돌이가 만들면 좋은 Rules", + "쓰레기 배출 요일 확인하고 정리하기!\n방 안에서 음식물 섭취하지 않기!", "오케바리~ 알겠다!"), + ("2022-01-01", "2022-01-01", "https://team-hous.s3.ap-northeast-2.amazonaws.com/personality/red.png", + "슈퍼 팔로워 삼각이", "GREEN", + "주변에 관심이 많고 전반적인 생활 영역에서\n높은 수준의 섬세함을 지녀 다른 룸메이트들의\n생활도 세심하게 배려해줄 수 있어요.\n육각이님과 함께 생활하는 룸메이트를 위한 Tip!\n우리 집 Rules 추천을 받아보는 건 어떤가요?", + "https://team-hous.s3.ap-northeast-2.amazonaws.com/personality/purple.png", "하이레벨 오돌이", + "https://team-hous.s3.ap-northeast-2.amazonaws.com/personality/green.png", "룰 세터 육각이", "육각이가 만들면 좋은 Rules", + "빨래가 끝나면 바로 옷 꺼내기!\n샤워 후 머리카락 치우기!", "나는 공동생활 백과사전!"); + +INSERT INTO personality_test +(created_at, updated_at, answers, idx, image_url, question, question_type) +VALUES ("2022-01-01", "2022-01-01", "스탠드를 키고 자 방이 매우 밝다.\n햇빛이 비춰 자연스럽게 방을 밝힌다.\n암막 커튼이 쳐져있어, 완전히 어둡다.", 1, + "https://team-hous.s3.ap-northeast-2.amazonaws.com/personality-test/test-01.png", "알람 소리에 눈을 뜬 당신\n방 안은 어떤가요?", + "LIGHT"), + ("2022-01-01", "2022-01-01", + "어? 샴푸를 다 썼네? 미래의 내가 치우겠지~\t하며 일단 아무데나 둔다.\n지금은 바쁘니 외출 후 치워야지!\t욕실 문 근처에 둔다.\n미리미리 치워둬야 고생을 안 해.\t샴푸통을 분리해 재활용으로 버린다.", + 2, "https://team-hous.s3.ap-northeast-2.amazonaws.com/personality-test/test-02.png", + "외출 준비를 하려는데\n샴푸통이 비어있는 것 같다.", "CLEAN"), + ("2022-01-01", "2022-01-01", + "입었던 옷, 빨래한 옷들이 뒤죽박죽 섞여있다.\n입었던 옷은 대충 놓여 있지만,\t빨래한 옷들은 개어져 있다.\n깔끔하게 정리된 옷장!\t모든 옷이 잘 정리되어 개어있다.", 3, + "https://team-hous.s3.ap-northeast-2.amazonaws.com/personality-test/test-03.png", "옷을 입으려 옷장을 열었다.\n옷장의 상태는?", + "CLEAN"), + ("2022-01-01", "2022-01-01", "냄새? 음, 잘 모르겠는데?\n조금 나는 것 같긴 한데,\t그래도 이 정도면 괜찮아~\n어우, 잘못 세탁했다. 다시 빨아야겠는데?", 4, + "https://team-hous.s3.ap-northeast-2.amazonaws.com/personality-test/test-04.png", + "집을 나서는데 룸메이트가 덜 마른 옷을\n내밀며 냄새가 나는지 묻는다면?", "SMELL"), + ("2022-01-01", "2022-01-01", "어, 뭐야? 공사하네! 언제 시작했지?\n아, 간간히 들리던 소리가 공사소리였구나!\n어쩐지 많이 시끄럽더라, 공사야 빨리 끝나라!", 5, + "https://team-hous.s3.ap-northeast-2.amazonaws.com/personality-test/test-05.png", "집 밖으로 나오니\n집 앞 공사 환경이 보인다.", + "NOISE"), + ("2022-01-01", "2022-01-01", "음, 향수 냄세네! 하고 갈 길을 간다.\n아, 냄새... 향수 뿌렸나 보네?\n향수 냄새가 심하네... 라고 생각하며\t빨리 걷는다.", 6, + "https://team-hous.s3.ap-northeast-2.amazonaws.com/personality-test/test-06.png", + "약속장소를 가는 길,\n진한 향수를 뿌린 사람이 지나간다.", "SMELL"), + ("2022-01-01", "2022-01-01", "내가 분위기 메이커!\t바로 새로운 이야기를 꺼낸다.\n가끔씩 궁금한 걸 물으며 말을 해보려 한다.\n오히려 편하다, 정적을 즐긴다.", 7, + "https://team-hous.s3.ap-northeast-2.amazonaws.com/personality-test/test-07.png", + "친구와 식당에 도착해\n주문을 하고 나니 순간 정적이 찾아왔다.", "INTROVERSION"), + ("2022-01-01", "2022-01-01", + "생활하다보면 그 정도 소음은 나지.\t 괜찮다고 한다.\n조금 신경쓰이긴 해~ 라고 말하며\t스몰토크를 이어나간다.\n여전히 시끄러워서 어떻게 말을 해야\t할지 고민 중이라고 이야기한다.", 8, + "https://team-hous.s3.ap-northeast-2.amazonaws.com/personality-test/test-08.png", + "친구가 옆 방에서 들린다고 했던\n음악소리는 괜찮은지 물어본다.", "NOISE"), + ("2022-01-01", "2022-01-01", + "반갑게 인사하고 여러가지 안부를 묻는다.\n다가가 간단히 인사를 하며\tK-약속만 잡고 헤어진다.\n반갑긴 하지만 부담스러워..\t나를 못 알아봤길 바라면서 조용히 지나친다.", 9, + "https://team-hous.s3.ap-northeast-2.amazonaws.com/personality-test/test-09.png", + "식사를 마치고 식당을 나서는데\n저 멀리 왠지 낯익은 얼굴이 보인다.", "INTROVERSION"), + ("2022-01-01", "2022-01-01", + "와, 맛있겠다! 음식 냄새가 좋다고 생각한다.\n음식 냄새가 조금 신경 쓰이지만 내 방까지\t풍기는 것은 아니니 괜찮다고 생각한다.\n조용히 창문을 열어 환기시킨다.", 10, + "https://team-hous.s3.ap-northeast-2.amazonaws.com/personality-test/test-10.png", + "다시 돌아온 집, 룸메이트가\n배달 음식을 거실에서 먹고 있다.", "SMELL"), + ("2022-01-01", "2022-01-01", + "침대에는 옷들, 책상 위는 보던 책.\t마구 섞여 있지만 나만의 규칙은 있다.\n엄청 깔끔하진 않지만 어느 정도 정리되어 있다.\n깔끔하게 정돈된 공간이 안정감을 준다.", 11, + "https://team-hous.s3.ap-northeast-2.amazonaws.com/personality-test/test-11.png", + "친구를 뒤로 하고 내 방에 도착했다.\n내 방의 상태는?", "CLEAN"), + ("2022-01-01", "2022-01-01", + "쉬는 날 친구 만나고 놀아야지~\t바로 전화해 약속을 잡는다.\n음, 일단 약속을 잡지는 말고\t연락오면 나가자.\n집에서 충전할 시간이 필요해\t침대랑 합체!", 12, + "https://team-hous.s3.ap-northeast-2.amazonaws.com/personality-test/test-12.png", + "책상에 앉아 일정을 정리하는데\n내일은 쉬는 날, 친구와 약속을 잡을까?", "INTROVERSION"), + ("2022-01-01", "2022-01-01", + "문이 살짝 열려 있어 복도의 불빛이 보이지만\t특별히 불편함을 느끼지 않고 바로 잠든다.\n불을 껐지만 모니터 깜빡임이 조금\t신경쓰여 뒤척이다 잠에 든다.\n잠을 잘 때는 어두운 게 좋아\t안대를 끼고 잔다.", + 13, "https://team-hous.s3.ap-northeast-2.amazonaws.com/personality-test/test-13.png", "하루를 마무리하고 잘 준비를 마쳤다.", + "LIGHT"), + ("2022-01-01", "2022-01-01", + "아침에 확인해야지,\t별 생각 없이 무시하고 잔다.\n진동이 조금 신경쓰이지만 계속\t울리지는 않겠지 생각하며 잠을 청한다.\n바로 전화를 무음모드로 돌려놓는다.", 14, + "https://team-hous.s3.ap-northeast-2.amazonaws.com/personality-test/test-14.png", "잠들기 직전 진동으로 해놓은\n전화가 울린다.", + "NOISE"), + ("2022-01-01", "2022-01-01", + "스탠드를 켠지도 모르고 잘 잔다.\n조금 뒤척이다 스탠드 쪽을\t등지고 잠을 청한다.\n침대에서 일어나 친구에게 스탠드\t불을 줄여달라고 이야기한다.", 15, + "https://team-hous.s3.ap-northeast-2.amazonaws.com/personality-test/test-15.png", + "모두가 자는 새벽,\n갑자기 친구가 스탠드를 밝게 켰다.", "LIGHT"); + +INSERT INTO badge + (created_at, updated_at, info, image_url) +VALUES ("2022-01-01", "2022-01-01", "POUNDING_HOUSE", + "https://team-hous.s3.ap-northeast-2.amazonaws.com/badge/pounding-house.png"), + ("2022-01-01", "2022-01-01", "I_AM_SUCH_A_PERSON", + "https://team-hous.s3.ap-northeast-2.amazonaws.com/badge/i-am-such-a-person.png"), + ("2022-01-01", "2022-01-01", "OUR_HOUSE_HOMIES", + "https://team-hous.s3.ap-northeast-2.amazonaws.com/badge/our-house-homies.png"), + ("2022-01-01", "2022-01-01", "I_DONT_EVEN_KNOW_ME", + "https://team-hous.s3.ap-northeast-2.amazonaws.com/badge/i-dont-even-know-me.png"), + ("2022-01-01", "2022-01-01", "HOMIE_IS_BORN", + "https://team-hous.s3.ap-northeast-2.amazonaws.com/badge/homie-is-born.png"), + ("2022-01-01", "2022-01-01", "TODO_ONE_STEP", + "https://team-hous.s3.ap-northeast-2.amazonaws.com/badge/todo-one-step.png"), + ("2022-01-01", "2022-01-01", "GOOD_JOB", "https://team-hous.s3.ap-northeast-2.amazonaws.com/badge/good-job.png"), + ("2022-01-01", "2022-01-01", "SINCERITY_KING_HOMIE", + "https://team-hous.s3.ap-northeast-2.amazonaws.com/badge/sincerity-king-homie.png"), + ("2022-01-01", "2022-01-01", "TODO_MASTER", + "https://team-hous.s3.ap-northeast-2.amazonaws.com/badge/todo-master.png"), + ("2022-01-01", "2022-01-01", "LETS_BUILD_A_POLE", + "https://team-hous.s3.ap-northeast-2.amazonaws.com/badge/lets-build-a-pole.png"), + ("2022-01-01", "2022-01-01", "OUR_HOUSE_PILLAR_HOMIE", + "https://team-hous.s3.ap-northeast-2.amazonaws.com/badge/our-house-pillar-homie.png"), + ("2022-01-01", "2022-01-01", "FEEDBACK_ONE_STEP", + "https://team-hous.s3.ap-northeast-2.amazonaws.com/badge/feedback-one-step.png"); + +INSERT INTO deploy + (id, created_at, updated_at, os, version, market_url) +VALUES (1, "2022-12-01", "2022-12-01", "iOS", "1.0.0", "https://apps.apple.com/kr/app/hous-/id1659976144"), + (2, "2022-12-01", "2022-12-01", "AOS", "1.0.1", + "https://play.google.com/store/apps/details?id=hous.release.androidhttps://play.google.com/store/apps/details?id=hous.release.android"); diff --git a/src/main/resources/sql/schema.sql b/src/main/resources/sql/schema.sql new file mode 100644 index 00000000..898c34ad --- /dev/null +++ b/src/main/resources/sql/schema.sql @@ -0,0 +1,229 @@ +DROP TABLE IF EXISTS badge; +DROP TABLE IF EXISTS deploy; +DROP TABLE IF EXISTS feedback; +DROP TABLE IF EXISTS personality; +DROP TABLE IF EXISTS personality_test; +DROP TABLE IF EXISTS setting; +DROP TABLE IF EXISTS test_score; +DROP TABLE IF EXISTS user; +DROP TABLE IF EXISTS onboarding; +DROP TABLE IF EXISTS acquire; +DROP TABLE IF EXISTS notification; +DROP TABLE IF EXISTS represent; +DROP TABLE IF EXISTS room; +DROP TABLE IF EXISTS participate; +DROP TABLE IF EXISTS rule; +DROP TABLE IF EXISTS todo; +DROP TABLE IF EXISTS done; +DROP TABLE IF EXISTS take; +DROP TABLE IF EXISTS redo; + + +CREATE TABLE badge +( + id bigint auto_increment primary key, + created_at datetime(6) null, + updated_at datetime(6) null, + image_url varchar(300) not null, + info varchar(30) not null +); + +CREATE TABLE deploy +( + id bigint auto_increment primary key, + created_at datetime(6) null, + updated_at datetime(6) null, + market_url varchar(300) not null, + os varchar(30) not null, + version varchar(30) not null +); + +CREATE TABLE feedback +( + id bigint auto_increment primary key, + created_at datetime(6) null, + updated_at datetime(6) null, + comment varchar(300) null, + feedback_type varchar(30) null +); + +CREATE TABLE personality +( + id bigint auto_increment primary key, + created_at datetime(6) null, + updated_at datetime(6) null, + bad_personality_image_url varchar(300) not null, + bad_personality_name varchar(300) not null, + color varchar(30) not null, + description varchar(500) not null, + good_personality_image_url varchar(300) not null, + good_personality_name varchar(300) not null, + image_url varchar(300) not null, + name varchar(30) not null, + recommend_title varchar(300) not null, + recommend_todo varchar(300) not null, + title varchar(300) not null +); + +CREATE TABLE personality_test +( + id bigint auto_increment primary key, + created_at datetime(6) null, + updated_at datetime(6) null, + answers varchar(300) not null, + idx int not null, + image_url varchar(300) not null, + question varchar(300) not null, + question_type varchar(30) not null +); + +CREATE TABLE setting +( + id bigint auto_increment primary key, + created_at datetime(6) null, + updated_at datetime(6) null, + badge_push_status varchar(30) not null, + is_push_notification bit not null, + new_todo_push_status varchar(30) not null, + remind_todo_push_status varchar(30) not null, + rules_push_status varchar(30) not null, + today_todo_push_status varchar(30) not null +); + +CREATE TABLE test_score +( + id bigint auto_increment primary key, + created_at datetime(6) null, + updated_at datetime(6) null, + clean int not null, + introversion int not null, + light int not null, + noise int not null, + smell int not null +); + +CREATE TABLE user +( + id bigint auto_increment primary key, + created_at datetime(6) null, + updated_at datetime(6) null, + fcm_token varchar(300) null, + social_id varchar(300) not null, + social_type varchar(30) not null, + status varchar(30) not null, + setting_id bigint not null, + constraint UK_3i3vte4rqus8rvevykm874whj unique (fcm_token) +); + +CREATE TABLE onboarding +( + id bigint auto_increment primary key, + created_at datetime(6) null, + updated_at datetime(6) null, + birthday varchar(255) not null, + introduction varchar(100) null, + is_public bit not null, + job varchar(30) null, + mbti varchar(30) null, + nickname varchar(30) not null, + personality_id bigint not null, + test_score_id bigint null, + user_id bigint not null +); + +CREATE TABLE acquire +( + id bigint auto_increment primary key, + created_at datetime(6) null, + updated_at datetime(6) null, + is_read bit not null, + badge_id bigint null, + onboarding_id bigint null +); + +CREATE TABLE notification +( + id bigint auto_increment primary key, + created_at datetime(6) null, + updated_at datetime(6) null, + content varchar(100) not null, + is_read bit not null, + type varchar(30) not null, + onboarding_id bigint null +); + +CREATE TABLE represent +( + id bigint auto_increment primary key, + created_at datetime(6) null, + updated_at datetime(6) null, + badge_id bigint null, + onboarding_id bigint null +); + +CREATE TABLE room +( + id bigint auto_increment primary key, + created_at datetime(6) null, + updated_at datetime(6) null, + code varchar(30) not null, + name varchar(30) not null, + participants_cnt int not null, + onboarding_id bigint not null +); + +CREATE TABLE participate +( + id bigint auto_increment primary key, + created_at datetime(6) null, + updated_at datetime(6) null, + onboarding_id bigint null, + room_id bigint null +); + +CREATE TABLE rule +( + id bigint auto_increment primary key, + created_at datetime(6) null, + updated_at datetime(6) null, + idx int not null, + name varchar(100) not null, + room_id bigint null +); + +CREATE TABLE todo +( + id bigint auto_increment primary key, + created_at datetime(6) null, + updated_at datetime(6) null, + is_push_notification bit not null, + name varchar(100) not null, + room_id bigint null +); + +CREATE TABLE done +( + id bigint auto_increment primary key, + created_at datetime(6) null, + updated_at datetime(6) null, + onboarding_id bigint null, + todo_id bigint null +); + +CREATE TABLE take +( + id bigint auto_increment primary key, + created_at datetime(6) null, + updated_at datetime(6) null, + onboarding_id bigint null, + todo_id bigint not null +); + +CREATE TABLE redo +( + id bigint auto_increment primary key, + created_at datetime(6) null, + updated_at datetime(6) null, + day_of_week varchar(30) not null, + take_id bigint null +); diff --git a/src/test/java/hous/server/service/room/RoomServiceTest.java b/src/test/java/hous/server/service/room/RoomServiceTest.java new file mode 100644 index 00000000..979d60e1 --- /dev/null +++ b/src/test/java/hous/server/service/room/RoomServiceTest.java @@ -0,0 +1,297 @@ +package hous.server.service.room; + +import hous.server.domain.badge.Represent; +import hous.server.domain.badge.repository.AcquireRepository; +import hous.server.domain.badge.repository.RepresentRepository; +import hous.server.domain.notification.repository.NotificationRepository; +import hous.server.domain.personality.PersonalityColor; +import hous.server.domain.personality.repository.PersonalityRepository; +import hous.server.domain.room.Participate; +import hous.server.domain.room.Room; +import hous.server.domain.room.repository.ParticipateRepository; +import hous.server.domain.room.repository.RoomRepository; +import hous.server.domain.rule.repository.RuleRepository; +import hous.server.domain.todo.DayOfWeek; +import hous.server.domain.todo.Redo; +import hous.server.domain.todo.Take; +import hous.server.domain.todo.Todo; +import hous.server.domain.todo.repository.RedoRepository; +import hous.server.domain.todo.repository.TakeRepository; +import hous.server.domain.todo.repository.TodoRepository; +import hous.server.domain.user.Onboarding; +import hous.server.domain.user.TestScore; +import hous.server.domain.user.User; +import hous.server.domain.user.UserSocialType; +import hous.server.domain.user.repository.OnboardingRepository; +import hous.server.domain.user.repository.TestScoreRepository; +import hous.server.domain.user.repository.UserRepository; +import hous.server.service.room.dto.request.SetRoomNameRequestDto; +import hous.server.service.todo.TodoService; +import hous.server.service.todo.dto.request.TodoInfoRequestDto; +import hous.server.service.user.UserService; +import hous.server.service.user.dto.request.CreateUserRequestDto; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.test.context.ActiveProfiles; + +import javax.transaction.Transactional; +import java.util.List; + +import static org.assertj.core.api.Assertions.assertThat; + +@SpringBootTest +@ActiveProfiles(value = "local") +public class RoomServiceTest { + + @Autowired + private UserRepository userRepository; + + @Autowired + private OnboardingRepository onboardingRepository; + + @Autowired + private RoomRepository roomRepository; + + @Autowired + private ParticipateRepository participateRepository; + + @Autowired + private RedoRepository redoRepository; + + @Autowired + private TakeRepository takeRepository; + + @Autowired + private TodoRepository todoRepository; + + @Autowired + private AcquireRepository acquireRepository; + + @Autowired + private NotificationRepository notificationRepository; + + @Autowired + private RepresentRepository representRepository; + + @Autowired + private TestScoreRepository testScoreRepository; + + @Autowired + private PersonalityRepository personalityRepository; + + @Autowired + private RuleRepository ruleRepository; + + @Autowired + private UserService userService; + + @Autowired + private RoomService roomService; + + @Autowired + private TodoService todoService; + + @BeforeEach + public void reset() { + redoRepository.deleteAllInBatch(); + takeRepository.deleteAllInBatch(); + todoRepository.deleteAllInBatch(); + participateRepository.deleteAllInBatch(); + acquireRepository.deleteAllInBatch(); + ruleRepository.deleteAllInBatch(); + representRepository.deleteAllInBatch(); + testScoreRepository.deleteAllInBatch(); + roomRepository.deleteAllInBatch(); + notificationRepository.deleteAllInBatch(); + onboardingRepository.deleteAllInBatch(); + userRepository.deleteAllInBatch(); + } + + @Test + @DisplayName("방에 들어가자마자 나가기 성공") + @Transactional + public void leave_room_success() { + // given + CreateUserRequestDto createUserRequestDto = CreateUserRequestDto.of( + "socialId1", UserSocialType.KAKAO, "fcmToken1", "nickname1", "2022-01-01", true); + Long userId = userService.registerUser(createUserRequestDto); + User user = userRepository.findUserById(userId); + + SetRoomNameRequestDto setRoomNameRequestDto = SetRoomNameRequestDto.of("room1"); + roomService.createRoom(setRoomNameRequestDto, userId); + + TodoInfoRequestDto todoInfoRequestDto = TodoInfoRequestDto.of("todo1", true, + List.of(TodoInfoRequestDto.TodoUser.builder() + .onboardingId(user.getOnboarding().getId()) + .dayOfWeeks(List.of(DayOfWeek.MONDAY, DayOfWeek.WEDNESDAY, DayOfWeek.FRIDAY)) + .build())); + todoService.createTodo(todoInfoRequestDto, userId); + + // when + roomService.leaveRoom(userId); + + // then + List rooms = roomRepository.findAll(); + assertThat(rooms).isEmpty(); + + // 방을 나간 후 내가 추가한 할일이 삭제되었는지 확인 + List todos = todoRepository.findAll(); + List takes = takeRepository.findAll(); + List redos = redoRepository.findAll(); + assertThat(todos).isEmpty(); + assertThat(takes).isEmpty(); + assertThat(redos).isEmpty(); + + // 방을 나간 후 나의 정보들이 삭제되었는지 확인 + List onboardings = onboardingRepository.findAll(); + assertThat(onboardings).hasSize(1); + Onboarding onboarding = onboardings.get(0); + + List represents = representRepository.findAll(); + assertThat(represents).isEmpty(); + List testScores = testScoreRepository.findAll(); + assertThat(testScores).isEmpty(); + assertThat(onboarding.getPersonality()).isEqualTo(personalityRepository.findPersonalityByColor(PersonalityColor.GRAY)); + assertThat(onboarding.isPublic()).isFalse(); + assertThat(onboarding.getMbti()).isNull(); + assertThat(onboarding.getJob()).isNull(); + assertThat(onboarding.getIntroduction()).isNull(); + assertThat(onboarding.getTestScore()).isNull(); + assertThat(onboarding.getRepresent()).isNull(); + } + + @Test + @DisplayName("방에 여러명 참여할 때 주인이 아닌 사람이 나가기 성공") + @Transactional + public void leave_room_by_participate_success() { + // given + CreateUserRequestDto createUserRequestDto1 = CreateUserRequestDto.of( + "socialId1", UserSocialType.KAKAO, "fcmToken1", "nickname1", "2022-01-01", true); + Long owner = userService.registerUser(createUserRequestDto1); + User ownerUser = userRepository.findUserById(owner); + + CreateUserRequestDto createUserRequestDto2 = CreateUserRequestDto.of( + "socialId2", UserSocialType.KAKAO, "fcmToken2", "nickname2", "2022-01-01", true); + Long userId2 = userService.registerUser(createUserRequestDto2); + User user2 = userRepository.findUserById(userId2); + + CreateUserRequestDto createUserRequestDto3 = CreateUserRequestDto.of( + "socialId3", UserSocialType.KAKAO, "fcmToken3", "nickname3", "2022-01-01", true); + Long userId3 = userService.registerUser(createUserRequestDto3); + + SetRoomNameRequestDto setRoomNameRequestDto = SetRoomNameRequestDto.of("room1"); + Long roomId = roomService.createRoom(setRoomNameRequestDto, owner).getRoomId(); + roomService.joinRoom(roomId, userId2); + roomService.joinRoom(roomId, userId3); + + TodoInfoRequestDto todoInfoRequestDto = TodoInfoRequestDto.of("todo1", true, + List.of(TodoInfoRequestDto.TodoUser.builder() + .onboardingId(ownerUser.getOnboarding().getId()) + .dayOfWeeks(List.of(DayOfWeek.MONDAY, DayOfWeek.WEDNESDAY, DayOfWeek.FRIDAY)) + .build(), + TodoInfoRequestDto.TodoUser.builder() + .onboardingId(user2.getOnboarding().getId()) + .dayOfWeeks(List.of(DayOfWeek.TUESDAY, DayOfWeek.THURSDAY)) + .build())); + todoService.createTodo(todoInfoRequestDto, userId2); + + // when + roomService.leaveRoom(userId2); + + // then + List rooms = roomRepository.findAll(); + assertThat(rooms).hasSize(1); + List participates = participateRepository.findAll(); + assertThat(participates).hasSize(2); + assertThat(owner).isEqualTo(rooms.get(0).getOwner().getUser().getId()); + + // 방을 나간 후 나간 유저가(userId2) 담당자에서 빠졌는지 확인 + List todos = todoRepository.findAll(); + List takes = takeRepository.findAll(); + List redos = redoRepository.findAll(); + assertThat(todos).hasSize(1); + assertThat(takes).hasSize(1); + assertThat(redos).hasSize(3); + assertThat(takes.get(0).getOnboarding().getUser().getId()).isEqualTo(owner); + + // 방을 나간 후 나의 정보들이 삭제되었는지 확인 + User user = userRepository.findUserById(userId2); + Onboarding onboarding = user.getOnboarding(); + assertThat(onboarding.getPersonality()).isEqualTo(personalityRepository.findPersonalityByColor(PersonalityColor.GRAY)); + assertThat(onboarding.isPublic()).isFalse(); + assertThat(onboarding.getMbti()).isNull(); + assertThat(onboarding.getJob()).isNull(); + assertThat(onboarding.getIntroduction()).isNull(); + assertThat(onboarding.getTestScore()).isNull(); + assertThat(onboarding.getRepresent()).isNull(); + } + + @Test + @DisplayName("방에 여러명 참여할 때 주인이 나가기 성공 후 owner 넘겨주기 성공") + @Transactional + public void leave_room_by_owner_success() { + // given + CreateUserRequestDto createUserRequestDto1 = CreateUserRequestDto.of( + "socialId1", UserSocialType.KAKAO, "fcmToken1", "nickname1", "2022-01-01", true); + Long owner = userService.registerUser(createUserRequestDto1); + User ownerUser = userRepository.findUserById(owner); + + CreateUserRequestDto createUserRequestDto2 = CreateUserRequestDto.of( + "socialId2", UserSocialType.KAKAO, "fcmToken2", "nickname2", "2022-01-01", true); + Long userId2 = userService.registerUser(createUserRequestDto2); + User user2 = userRepository.findUserById(userId2); + + CreateUserRequestDto createUserRequestDto3 = CreateUserRequestDto.of( + "socialId3", UserSocialType.KAKAO, "fcmToken3", "nickname3", "2022-01-01", true); + Long userId3 = userService.registerUser(createUserRequestDto3); + + SetRoomNameRequestDto setRoomNameRequestDto = SetRoomNameRequestDto.of("room1"); + Long roomId = roomService.createRoom(setRoomNameRequestDto, owner).getRoomId(); + roomService.joinRoom(roomId, userId2); + roomService.joinRoom(roomId, userId3); + + TodoInfoRequestDto todoInfoRequestDto = TodoInfoRequestDto.of("todo1", true, + List.of(TodoInfoRequestDto.TodoUser.builder() + .onboardingId(ownerUser.getOnboarding().getId()) + .dayOfWeeks(List.of(DayOfWeek.MONDAY, DayOfWeek.WEDNESDAY, DayOfWeek.FRIDAY)) + .build(), + TodoInfoRequestDto.TodoUser.builder() + .onboardingId(user2.getOnboarding().getId()) + .dayOfWeeks(List.of(DayOfWeek.TUESDAY, DayOfWeek.THURSDAY)) + .build())); + todoService.createTodo(todoInfoRequestDto, userId2); + + // when + roomService.leaveRoom(owner); + + // then + List rooms = roomRepository.findAll(); + assertThat(rooms).hasSize(1); + List participates = rooms.get(0).getParticipates(); + assertThat(participates).hasSize(2); + assertThat(userId2).isEqualTo(rooms.get(0).getOwner().getUser().getId()); // 두번째로 들어간 사람이 주인이 된다. + + // 방을 나간 후 나간 유저가(owner) 담당자에서 빠졌는지 확인 + List todos = todoRepository.findAll(); + List takes = takeRepository.findAll(); + List redos = redoRepository.findAll(); + assertThat(todos).hasSize(1); + assertThat(takes).hasSize(1); + assertThat(redos).hasSize(2); + assertThat(takes.get(0).getOnboarding().getUser().getId()).isEqualTo(userId2); + + // 방을 나간 후 나의 정보들이 삭제되었는지 확인 + User user = userRepository.findUserById(owner); + Onboarding onboarding = user.getOnboarding(); + assertThat(onboarding.getPersonality()).isEqualTo(personalityRepository.findPersonalityByColor(PersonalityColor.GRAY)); + assertThat(onboarding.isPublic()).isFalse(); + assertThat(onboarding.getMbti()).isNull(); + assertThat(onboarding.getJob()).isNull(); + assertThat(onboarding.getIntroduction()).isNull(); + assertThat(onboarding.getTestScore()).isNull(); + assertThat(onboarding.getRepresent()).isNull(); + } +} diff --git a/src/test/java/hous/server/service/rule/RuleServiceTest.java b/src/test/java/hous/server/service/rule/RuleServiceTest.java new file mode 100644 index 00000000..2cd9592c --- /dev/null +++ b/src/test/java/hous/server/service/rule/RuleServiceTest.java @@ -0,0 +1,222 @@ +package hous.server.service.rule; + +import hous.server.common.exception.ConflictException; +import hous.server.common.exception.NotFoundException; +import hous.server.domain.badge.repository.AcquireRepository; +import hous.server.domain.notification.repository.NotificationRepository; +import hous.server.domain.room.repository.ParticipateRepository; +import hous.server.domain.room.repository.RoomRepository; +import hous.server.domain.rule.Rule; +import hous.server.domain.rule.repository.RuleRepository; +import hous.server.domain.user.User; +import hous.server.domain.user.UserSocialType; +import hous.server.domain.user.repository.OnboardingRepository; +import hous.server.domain.user.repository.UserRepository; +import hous.server.service.room.RoomService; +import hous.server.service.room.dto.request.SetRoomNameRequestDto; +import hous.server.service.room.dto.response.RoomInfoResponse; +import hous.server.service.rule.dto.request.CreateRuleRequestDto; +import hous.server.service.rule.dto.request.DeleteRuleReqeustDto; +import hous.server.service.user.UserService; +import hous.server.service.user.dto.request.CreateUserRequestDto; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.test.context.ActiveProfiles; + +import java.util.List; +import java.util.concurrent.CountDownLatch; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; +import java.util.stream.Collectors; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.AssertionsForClassTypes.assertThatThrownBy; + +@SpringBootTest +@ActiveProfiles(value = "local") +public class RuleServiceTest { + + @Autowired + private UserRepository userRepository; + + @Autowired + private OnboardingRepository onboardingRepository; + + @Autowired + private RoomRepository roomRepository; + + @Autowired + private ParticipateRepository participateRepository; + + @Autowired + private RuleRepository ruleRepository; + + @Autowired + private AcquireRepository acquireRepository; + + @Autowired + private NotificationRepository notificationRepository; + + @Autowired + private UserService userService; + + @Autowired + private RoomService roomService; + + @Autowired + private RuleService ruleService; + + @BeforeEach + public void reset() { + ruleRepository.deleteAllInBatch(); + participateRepository.deleteAllInBatch(); + acquireRepository.deleteAllInBatch(); + roomRepository.deleteAllInBatch(); + notificationRepository.deleteAllInBatch(); + onboardingRepository.deleteAllInBatch(); + userRepository.deleteAllInBatch(); + } + + @Test + @DisplayName("rule 동시에 2개 추가해도 성공") + public void create_two_rules_at_once_success() throws InterruptedException { + + // given + CreateUserRequestDto createUserRequestDto1 = CreateUserRequestDto.of( + "socialId1", UserSocialType.KAKAO, "fcmToken1", "nickname1", "2022-01-01", true); + CreateUserRequestDto createUserRequestDto2 = CreateUserRequestDto.of( + "socialId2", UserSocialType.KAKAO, "fcmToken2", "nickname2", "2022-01-01", true); + Long userId1 = userService.registerUser(createUserRequestDto1); + Long userId2 = userService.registerUser(createUserRequestDto2); + User user1 = userRepository.findUserById(userId1); + User user2 = userRepository.findUserById(userId2); + + SetRoomNameRequestDto setRoomNameRequestDto = SetRoomNameRequestDto.of("room1"); + RoomInfoResponse roomInfoResponse = roomService.createRoom(setRoomNameRequestDto, userId1); + roomService.joinRoom(roomInfoResponse.getRoomId(), userId2); + + CreateRuleRequestDto createRuleRequestDto1 = CreateRuleRequestDto.of(List.of("rule1")); + CreateRuleRequestDto createRuleRequestDto2 = CreateRuleRequestDto.of(List.of("rule2")); + + // when + ExecutorService executorService = Executors.newFixedThreadPool(2); + CountDownLatch countDownLatch = new CountDownLatch(2); + + for (int i = 1; i <= 2; i++) { + int finalI = i; + executorService.execute(() -> { + switch (finalI) { + case 1: + ruleService.createRule(createRuleRequestDto1, userId1); + break; + case 2: + ruleService.createRule(createRuleRequestDto2, userId2); + break; + } + countDownLatch.countDown(); + }); + } + + countDownLatch.await(); + + // then + List rules = ruleRepository.findAll(); + assertThat(rules.size()).isEqualTo(2); + } + + @Test + @DisplayName("이미 존재하는 rule 과 같은 이름을 가진 rule 추가할 경우 409 예외 발생") + public void create_duplicate_rule_name_throw_by_conflict_exception() { + // given + CreateUserRequestDto createUserRequestDto1 = CreateUserRequestDto.of( + "socialId1", UserSocialType.KAKAO, "fcmToken1", "nickname1", "2022-01-01", true); + Long userId = userService.registerUser(createUserRequestDto1); + + SetRoomNameRequestDto setRoomNameRequestDto = SetRoomNameRequestDto.of("room1"); + Long roomId = roomService.createRoom(setRoomNameRequestDto, userId).getRoomId(); + + CreateRuleRequestDto createRuleRequestDto = CreateRuleRequestDto.of(List.of("rule")); + ruleService.createRule(createRuleRequestDto, userId); + + // when, then + List rules = ruleRepository.findAll(); + assertThat(rules.size()).isEqualTo(1); + String matchedExceptionMessage = String.format("방 (%s) 에 이미 존재하는 ruleName (%s) 입니다.", roomId, "rule"); + assertThatThrownBy(() -> { + ruleService.createRule(createRuleRequestDto, userId); + }).isInstanceOf(ConflictException.class) + .hasMessageContaining(matchedExceptionMessage); + } + + @Test + @DisplayName("rule 1개 삭제 테스트") + public void delete_rule_test() { + // given + CreateUserRequestDto createUserRequestDto1 = CreateUserRequestDto.of( + "socialId1", UserSocialType.KAKAO, "fcmToken1", "nickname1", "2022-01-01", true); + Long userId = userService.registerUser(createUserRequestDto1); + + SetRoomNameRequestDto setRoomNameRequestDto = SetRoomNameRequestDto.of("room1"); + roomService.createRoom(setRoomNameRequestDto, userId); + + CreateRuleRequestDto createRuleRequestDto = CreateRuleRequestDto.of(List.of("rule1")); + ruleService.createRule(createRuleRequestDto, userId); + List deleteRuleIds = ruleRepository.findAll().stream().map(Rule::getId).collect(Collectors.toList()); + + // when + ruleService.deleteRules(DeleteRuleReqeustDto.of(deleteRuleIds), userId); + + // then + List rules = ruleRepository.findAll(); + assertThat(rules).isEmpty(); + } + + @Test + @DisplayName("rule 여러개 삭제 테스트") + public void delete_rules_test() { + // given + CreateUserRequestDto createUserRequestDto1 = CreateUserRequestDto.of( + "socialId1", UserSocialType.KAKAO, "fcmToken1", "nickname1", "2022-01-01", true); + Long userId = userService.registerUser(createUserRequestDto1); + CreateRuleRequestDto createRuleRequestDto = CreateRuleRequestDto.of(List.of("rule1, rule2, rule3")); + + SetRoomNameRequestDto setRoomNameRequestDto = SetRoomNameRequestDto.of("room1"); + roomService.createRoom(setRoomNameRequestDto, userId); + + ruleService.createRule(createRuleRequestDto, userId); + List deleteRuleIds = ruleRepository.findAll().stream().map(Rule::getId).collect(Collectors.toList()); + + // when + ruleService.deleteRules(DeleteRuleReqeustDto.of(deleteRuleIds), userId); + + // then + List rules = ruleRepository.findAll(); + assertThat(rules).isEmpty(); + } + + @Test + @DisplayName("rule 삭제 시 존재하지 않는 rule_id일 경우 404 예외 발생") + public void delete_rules_test_throw_by_notfound_exception() { + // given + CreateUserRequestDto createUserRequestDto1 = CreateUserRequestDto.of( + "socialId1", UserSocialType.KAKAO, "fcmToken1", "nickname1", "2022-01-01", true); + Long userId = userService.registerUser(createUserRequestDto1); + CreateRuleRequestDto createRuleRequestDto = CreateRuleRequestDto.of(List.of("rule1, rule2, rule3")); + + SetRoomNameRequestDto setRoomNameRequestDto = SetRoomNameRequestDto.of("room1"); + roomService.createRoom(setRoomNameRequestDto, userId); + + ruleService.createRule(createRuleRequestDto, userId); + List deleteRuleIds = List.of(4L, 5L, 6L); + + // when, then + String matchedExceptionMessage = String.format("존재하지 않는 규칙 (%s) 입니다", 4L); + assertThatThrownBy(() -> { + ruleService.deleteRules(DeleteRuleReqeustDto.of(deleteRuleIds), userId); + }).isInstanceOf(NotFoundException.class) + .hasMessageContaining(matchedExceptionMessage); + } +} diff --git a/src/test/java/hous/server/service/todo/TodoServiceTest.java b/src/test/java/hous/server/service/todo/TodoServiceTest.java new file mode 100644 index 00000000..bf3addee --- /dev/null +++ b/src/test/java/hous/server/service/todo/TodoServiceTest.java @@ -0,0 +1,255 @@ +package hous.server.service.todo; + +import hous.server.common.exception.ConflictException; +import hous.server.common.exception.NotFoundException; +import hous.server.domain.badge.repository.AcquireRepository; +import hous.server.domain.notification.repository.NotificationRepository; +import hous.server.domain.room.repository.ParticipateRepository; +import hous.server.domain.room.repository.RoomRepository; +import hous.server.domain.rule.repository.RuleRepository; +import hous.server.domain.todo.DayOfWeek; +import hous.server.domain.todo.Redo; +import hous.server.domain.todo.Take; +import hous.server.domain.todo.Todo; +import hous.server.domain.todo.repository.RedoRepository; +import hous.server.domain.todo.repository.TakeRepository; +import hous.server.domain.todo.repository.TodoRepository; +import hous.server.domain.user.User; +import hous.server.domain.user.UserSocialType; +import hous.server.domain.user.repository.OnboardingRepository; +import hous.server.domain.user.repository.UserRepository; +import hous.server.service.room.RoomService; +import hous.server.service.room.dto.request.SetRoomNameRequestDto; +import hous.server.service.room.dto.response.RoomInfoResponse; +import hous.server.service.todo.dto.request.TodoInfoRequestDto; +import hous.server.service.user.UserService; +import hous.server.service.user.dto.request.CreateUserRequestDto; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.test.context.ActiveProfiles; + +import java.util.List; +import java.util.concurrent.CountDownLatch; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.AssertionsForClassTypes.assertThatThrownBy; + +@SpringBootTest +@ActiveProfiles(value = "local") +public class TodoServiceTest { + + @Autowired + private UserRepository userRepository; + + @Autowired + private OnboardingRepository onboardingRepository; + + @Autowired + private RoomRepository roomRepository; + + @Autowired + private ParticipateRepository participateRepository; + + @Autowired + private RedoRepository redoRepository; + + @Autowired + private TakeRepository takeRepository; + + @Autowired + private TodoRepository todoRepository; + + @Autowired + private AcquireRepository acquireRepository; + + @Autowired + private NotificationRepository notificationRepository; + + @Autowired + private RuleRepository ruleRepository; + + @Autowired + private UserService userService; + + @Autowired + private RoomService roomService; + + @Autowired + private TodoService todoService; + + @BeforeEach + public void reset() { + redoRepository.deleteAllInBatch(); + takeRepository.deleteAllInBatch(); + todoRepository.deleteAllInBatch(); + participateRepository.deleteAllInBatch(); + acquireRepository.deleteAllInBatch(); + ruleRepository.deleteAllInBatch(); + roomRepository.deleteAllInBatch(); + notificationRepository.deleteAllInBatch(); + onboardingRepository.deleteAllInBatch(); + userRepository.deleteAllInBatch(); + } + + @Test + @DisplayName("todo 동시에 2개 추가해도 성공") + public void create_two_todos_at_once_success() throws InterruptedException { + + // given + CreateUserRequestDto createUserRequestDto1 = CreateUserRequestDto.of( + "socialId1", UserSocialType.KAKAO, "fcmToken1", "nickname1", "2022-01-01", true); + CreateUserRequestDto createUserRequestDto2 = CreateUserRequestDto.of( + "socialId2", UserSocialType.KAKAO, "fcmToken2", "nickname2", "2022-01-01", true); + Long userId1 = userService.registerUser(createUserRequestDto1); + Long userId2 = userService.registerUser(createUserRequestDto2); + User user1 = userRepository.findUserById(userId1); + User user2 = userRepository.findUserById(userId2); + + SetRoomNameRequestDto setRoomNameRequestDto = SetRoomNameRequestDto.of("room1"); + RoomInfoResponse roomInfoResponse = roomService.createRoom(setRoomNameRequestDto, userId1); + roomService.joinRoom(roomInfoResponse.getRoomId(), userId2); + + TodoInfoRequestDto todoInfoRequestDto1 = TodoInfoRequestDto.of("todo1", true, + List.of(TodoInfoRequestDto.TodoUser.builder() + .onboardingId(user1.getOnboarding().getId()) + .dayOfWeeks(List.of(DayOfWeek.MONDAY, DayOfWeek.WEDNESDAY, DayOfWeek.FRIDAY)) + .build(), + TodoInfoRequestDto.TodoUser.builder() + .onboardingId(user2.getOnboarding().getId()) + .dayOfWeeks(List.of(DayOfWeek.TUESDAY, DayOfWeek.THURSDAY)) + .build())); + TodoInfoRequestDto todoInfoRequestDto2 = TodoInfoRequestDto.of("todo1", true, + List.of(TodoInfoRequestDto.TodoUser.builder() + .onboardingId(user1.getOnboarding().getId()) + .dayOfWeeks(List.of(DayOfWeek.MONDAY, DayOfWeek.WEDNESDAY, DayOfWeek.FRIDAY)) + .build(), + TodoInfoRequestDto.TodoUser.builder() + .onboardingId(user2.getOnboarding().getId()) + .dayOfWeeks(List.of(DayOfWeek.TUESDAY, DayOfWeek.THURSDAY)) + .build())); + + // when + ExecutorService executorService = Executors.newFixedThreadPool(2); + CountDownLatch countDownLatch = new CountDownLatch(2); + + for (int i = 1; i <= 2; i++) { + int finalI = i; + executorService.execute(() -> { + switch (finalI) { + case 1: + todoService.createTodo(todoInfoRequestDto1, userId1); + break; + case 2: + todoService.createTodo(todoInfoRequestDto2, userId2); + break; + } + countDownLatch.countDown(); + }); + } + + countDownLatch.await(); + + // then + List todos = todoRepository.findAll(); + assertThat(todos.size()).isEqualTo(2); + } + + @Test + @DisplayName("이미 존재하는 rule 과 같은 이름을 가진 rule 추가할 경우 409 예외 발생") + public void create_duplicate_rule_name_throw_by_conflict_exception() { + // given + CreateUserRequestDto createUserRequestDto = CreateUserRequestDto.of( + "socialId1", UserSocialType.KAKAO, "fcmToken1", "nickname1", "2022-01-01", true); + Long userId = userService.registerUser(createUserRequestDto); + User user = userRepository.findUserById(userId); + + SetRoomNameRequestDto setRoomNameRequestDto = SetRoomNameRequestDto.of("room1"); + Long roomId = roomService.createRoom(setRoomNameRequestDto, userId).getRoomId(); + + TodoInfoRequestDto todoInfoRequestDto = TodoInfoRequestDto.of("todo1", true, + List.of(TodoInfoRequestDto.TodoUser.builder() + .onboardingId(user.getOnboarding().getId()) + .dayOfWeeks(List.of(DayOfWeek.MONDAY, DayOfWeek.WEDNESDAY, DayOfWeek.FRIDAY)) + .build())); + todoService.createTodo(todoInfoRequestDto, userId); + + // when, then + List todos = todoRepository.findAll(); + List takes = takeRepository.findAll(); + List redos = redoRepository.findAll(); + assertThat(todos.size()).isEqualTo(1); + assertThat(takes.size()).isEqualTo(1); + assertThat(redos.size()).isEqualTo(3); + String matchedExceptionMessage = String.format("방 (%s) 에 이미 존재하는 todo (%s) 입니다.", roomId, "todo1"); + assertThatThrownBy(() -> { + todoService.createTodo(todoInfoRequestDto, userId); + }).isInstanceOf(ConflictException.class) + .hasMessageContaining(matchedExceptionMessage); + } + + @Test + @DisplayName("todo 삭제 성공") + public void delete_todo() { + // given + CreateUserRequestDto createUserRequestDto = CreateUserRequestDto.of( + "socialId1", UserSocialType.KAKAO, "fcmToken1", "nickname1", "2022-01-01", true); + Long userId = userService.registerUser(createUserRequestDto); + User user = userRepository.findUserById(userId); + + SetRoomNameRequestDto setRoomNameRequestDto = SetRoomNameRequestDto.of("room1"); + roomService.createRoom(setRoomNameRequestDto, userId); + + TodoInfoRequestDto todoInfoRequestDto = TodoInfoRequestDto.of("todo1", true, + List.of(TodoInfoRequestDto.TodoUser.builder() + .onboardingId(user.getOnboarding().getId()) + .dayOfWeeks(List.of(DayOfWeek.MONDAY, DayOfWeek.WEDNESDAY, DayOfWeek.FRIDAY)) + .build())); + todoService.createTodo(todoInfoRequestDto, userId); + + + // when + Long todoId = todoRepository.findAll().get(0).getId(); + todoService.deleteTodo(todoId, userId); + + // then + List todos = todoRepository.findAll(); + List takes = takeRepository.findAll(); + List redos = redoRepository.findAll(); + assertThat(todos).isEmpty(); + assertThat(takes).isEmpty(); + assertThat(redos).isEmpty(); + } + + @Test + @DisplayName("todo 삭제 시 존재하지 않는 todo_id인 경우 404 예외 발생") + public void delete_rules_test_by_exception() { + // given + CreateUserRequestDto createUserRequestDto = CreateUserRequestDto.of( + "socialId1", UserSocialType.KAKAO, "fcmToken1", "nickname1", "2022-01-01", true); + Long userId = userService.registerUser(createUserRequestDto); + User user = userRepository.findUserById(userId); + + SetRoomNameRequestDto setRoomNameRequestDto = SetRoomNameRequestDto.of("room1"); + roomService.createRoom(setRoomNameRequestDto, userId); + + TodoInfoRequestDto todoInfoRequestDto = TodoInfoRequestDto.of("todo1", true, + List.of(TodoInfoRequestDto.TodoUser.builder() + .onboardingId(user.getOnboarding().getId()) + .dayOfWeeks(List.of(DayOfWeek.MONDAY, DayOfWeek.WEDNESDAY, DayOfWeek.FRIDAY)) + .build())); + todoService.createTodo(todoInfoRequestDto, userId); + + // when, then + Long unExistsTodoId = todoRepository.findAll().size() + 1L; + String matchedExceptionMessage = String.format("존재하지 않는 todo (%s) 입니다", unExistsTodoId); + assertThatThrownBy(() -> { + todoService.deleteTodo(2L, userId); + }).isInstanceOf(NotFoundException.class) + .hasMessageContaining(matchedExceptionMessage); + } +} diff --git a/src/test/java/hous/server/service/user/UserServiceTest.java b/src/test/java/hous/server/service/user/UserServiceTest.java new file mode 100644 index 00000000..72278bdb --- /dev/null +++ b/src/test/java/hous/server/service/user/UserServiceTest.java @@ -0,0 +1,118 @@ +package hous.server.service.user; + +import hous.server.domain.badge.repository.AcquireRepository; +import hous.server.domain.badge.repository.RepresentRepository; +import hous.server.domain.feedback.FeedbackType; +import hous.server.domain.notification.repository.NotificationRepository; +import hous.server.domain.personality.repository.PersonalityRepository; +import hous.server.domain.room.Room; +import hous.server.domain.room.repository.ParticipateRepository; +import hous.server.domain.room.repository.RoomRepository; +import hous.server.domain.rule.repository.RuleRepository; +import hous.server.domain.todo.repository.RedoRepository; +import hous.server.domain.todo.repository.TakeRepository; +import hous.server.domain.todo.repository.TodoRepository; +import hous.server.domain.user.User; +import hous.server.domain.user.UserSocialType; +import hous.server.domain.user.repository.OnboardingRepository; +import hous.server.domain.user.repository.TestScoreRepository; +import hous.server.domain.user.repository.UserRepository; +import hous.server.service.room.RoomService; +import hous.server.service.user.dto.request.CreateUserRequestDto; +import hous.server.service.user.dto.request.DeleteUserRequestDto; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.test.context.ActiveProfiles; + +import java.util.List; + +import static org.assertj.core.api.Assertions.assertThat; + +@SpringBootTest +@ActiveProfiles(value = "local") +public class UserServiceTest { + + @Autowired + private UserRepository userRepository; + + @Autowired + private OnboardingRepository onboardingRepository; + + @Autowired + private RoomRepository roomRepository; + + @Autowired + private ParticipateRepository participateRepository; + + @Autowired + private RedoRepository redoRepository; + + @Autowired + private TakeRepository takeRepository; + + @Autowired + private TodoRepository todoRepository; + + @Autowired + private AcquireRepository acquireRepository; + + @Autowired + private NotificationRepository notificationRepository; + + @Autowired + private RepresentRepository representRepository; + + @Autowired + private TestScoreRepository testScoreRepository; + + @Autowired + private PersonalityRepository personalityRepository; + + @Autowired + private RuleRepository ruleRepository; + + @Autowired + private UserService userService; + + @Autowired + private RoomService roomService; + + @BeforeEach + public void reset() { + redoRepository.deleteAllInBatch(); + takeRepository.deleteAllInBatch(); + todoRepository.deleteAllInBatch(); + participateRepository.deleteAllInBatch(); + acquireRepository.deleteAllInBatch(); + ruleRepository.deleteAllInBatch(); + representRepository.deleteAllInBatch(); + testScoreRepository.deleteAllInBatch(); + roomRepository.deleteAllInBatch(); + notificationRepository.deleteAllInBatch(); + onboardingRepository.deleteAllInBatch(); + userRepository.deleteAllInBatch(); + } + + // 정책상 방에 들어가지 않을 경우에만 사용자 삭제가 가능 + @Test + @DisplayName("방에 들어가지 않은 사용자 삭제 성공") + public void delete_user_by_not_join_room_success() { + // given + CreateUserRequestDto createUserRequestDto = CreateUserRequestDto.of( + "socialId1", UserSocialType.KAKAO, "fcmToken1", "nickname1", "2022-01-01", true); + Long userId = userService.registerUser(createUserRequestDto); + DeleteUserRequestDto deleteUserRequestDto = DeleteUserRequestDto.of(FeedbackType.NO, ""); + + // when + userService.deleteUser(deleteUserRequestDto, userId); + + // then + List users = userRepository.findAll(); + assertThat(users).isEmpty(); + List rooms = roomRepository.findAll(); + assertThat(rooms).isEmpty(); + } +}