From c991e8eeef3931a59a4c3eb0e0ea548d97df9171 Mon Sep 17 00:00:00 2001 From: 3juhwan <13selfesteem91@naver.com> Date: Thu, 18 Jul 2024 21:43:30 +0900 Subject: [PATCH 01/14] =?UTF-8?q?feat:=20=EC=9D=B8=EC=9B=90=20=EB=B3=80?= =?UTF-8?q?=EB=8F=99=20=EA=B8=B0=EB=8A=A5=20=EA=B5=AC=ED=98=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: kunsanglee --- .../application/MemberActionService.java | 66 +++++++++++++++ .../request/MemberActionSaveAppRequest.java | 11 +++ .../MemberActionSaveListAppRequest.java | 14 ++++ .../java/server/haengdong/domain/Action.java | 5 ++ .../server/haengdong/domain/MemberAction.java | 10 +++ .../haengdong/domain/MemberActionStatus.java | 9 ++ .../domain/MemberGroupIdProvider.java | 11 +++ .../persistence/ActionRepository.java | 9 ++ .../persistence/EventRepository.java | 2 + .../persistence/MemberActionRepository.java | 16 ++++ .../presentation/MemberActionController.java | 27 ++++++ .../request/MemberActionSaveListRequest.java | 16 ++++ .../request/MemberActionSaveRequest.java | 10 +++ .../application/MemberActionServiceTest.java | 82 +++++++++++++++++++ .../MemberActionControllerTest.java | 51 ++++++++++++ 15 files changed, 339 insertions(+) create mode 100644 server/src/main/java/server/haengdong/application/MemberActionService.java create mode 100644 server/src/main/java/server/haengdong/application/request/MemberActionSaveAppRequest.java create mode 100644 server/src/main/java/server/haengdong/application/request/MemberActionSaveListAppRequest.java create mode 100644 server/src/main/java/server/haengdong/domain/MemberGroupIdProvider.java create mode 100644 server/src/main/java/server/haengdong/persistence/ActionRepository.java create mode 100644 server/src/main/java/server/haengdong/persistence/MemberActionRepository.java create mode 100644 server/src/main/java/server/haengdong/presentation/MemberActionController.java create mode 100644 server/src/main/java/server/haengdong/presentation/request/MemberActionSaveListRequest.java create mode 100644 server/src/main/java/server/haengdong/presentation/request/MemberActionSaveRequest.java create mode 100644 server/src/test/java/server/haengdong/application/MemberActionServiceTest.java create mode 100644 server/src/test/java/server/haengdong/presentation/MemberActionControllerTest.java diff --git a/server/src/main/java/server/haengdong/application/MemberActionService.java b/server/src/main/java/server/haengdong/application/MemberActionService.java new file mode 100644 index 000000000..be3c81ff8 --- /dev/null +++ b/server/src/main/java/server/haengdong/application/MemberActionService.java @@ -0,0 +1,66 @@ +package server.haengdong.application; + +import java.util.ArrayList; +import java.util.List; +import java.util.stream.IntStream; +import lombok.RequiredArgsConstructor; +import org.springframework.stereotype.Service; +import server.haengdong.application.request.MemberActionSaveListAppRequest; +import server.haengdong.domain.Action; +import server.haengdong.domain.Event; +import server.haengdong.domain.MemberAction; +import server.haengdong.domain.MemberActionStatus; +import server.haengdong.domain.MemberGroupIdProvider; +import server.haengdong.persistence.ActionRepository; +import server.haengdong.persistence.EventRepository; +import server.haengdong.persistence.MemberActionRepository; + +@RequiredArgsConstructor +@Service +public class MemberActionService { + + private final MemberActionRepository memberActionRepository; + private final EventRepository eventRepository; + private final ActionRepository actionRepository; + private final MemberGroupIdProvider memberGroupIdProvider; + + public void saveMemberAction(String token, MemberActionSaveListAppRequest request) { + Event event = eventRepository.findByToken(token) + .orElseThrow(() -> new IllegalArgumentException("event not found")); + + List memberActions = memberActionRepository.findAllByEvent(event); + + request.actions().forEach( + action -> { + if (!isAvailableAction(memberActions, action.name(), action.status())) { + throw new IllegalArgumentException(); + } + } + ); + + List actions = new ArrayList<>(); + for (int i = 0; i < memberActions.size(); i++) { + Action action = new Action(event, request.sequence()); + actions.add(actionRepository.save(action)); + } + + Long memberGroupId = memberGroupIdProvider.createGroupId(); + List memberActionList = request.toMemberActionList(memberGroupId); + + IntStream.range(0, memberActionList.size()) + .forEach(i -> memberActionList.get(i).setAction(actions.get(i))); + + memberActionRepository.saveAll(memberActionList); + } + + private boolean isAvailableAction(List actions, String name, String status) { + MemberActionStatus memberActionStatus = MemberActionStatus.of(status); + for (int i = actions.size() - 1; i >= 0; i--) { + MemberAction action = actions.get(i); + if (action.getMemberName().equals(name)) { + return action.getStatus() != memberActionStatus; + } + } + return memberActionStatus == MemberActionStatus.IN; + } +} diff --git a/server/src/main/java/server/haengdong/application/request/MemberActionSaveAppRequest.java b/server/src/main/java/server/haengdong/application/request/MemberActionSaveAppRequest.java new file mode 100644 index 000000000..66310a96e --- /dev/null +++ b/server/src/main/java/server/haengdong/application/request/MemberActionSaveAppRequest.java @@ -0,0 +1,11 @@ +package server.haengdong.application.request; + +import server.haengdong.domain.MemberAction; +import server.haengdong.domain.MemberActionStatus; + +public record MemberActionSaveAppRequest(String name, String status) { + + public MemberAction toMemberAction(Long memberGroupId) { + return new MemberAction(name, MemberActionStatus.of(status), memberGroupId); + } +} diff --git a/server/src/main/java/server/haengdong/application/request/MemberActionSaveListAppRequest.java b/server/src/main/java/server/haengdong/application/request/MemberActionSaveListAppRequest.java new file mode 100644 index 000000000..370d57446 --- /dev/null +++ b/server/src/main/java/server/haengdong/application/request/MemberActionSaveListAppRequest.java @@ -0,0 +1,14 @@ +package server.haengdong.application.request; + +import java.util.List; +import server.haengdong.domain.MemberAction; + +public record MemberActionSaveListAppRequest(List actions, Long sequence) { + + public List toMemberActionList(Long memberGroupId) { + return actions.stream() + .map(action -> action.toMemberAction(memberGroupId)) + .toList(); + + } +} diff --git a/server/src/main/java/server/haengdong/domain/Action.java b/server/src/main/java/server/haengdong/domain/Action.java index 7f782a1ac..7a47b1de5 100644 --- a/server/src/main/java/server/haengdong/domain/Action.java +++ b/server/src/main/java/server/haengdong/domain/Action.java @@ -23,4 +23,9 @@ public class Action { private Event event; private Long sequence; + + public Action(Event event, Long sequence) { + this.event = event; + this.sequence = sequence; + } } diff --git a/server/src/main/java/server/haengdong/domain/MemberAction.java b/server/src/main/java/server/haengdong/domain/MemberAction.java index 6d8ea9b20..4a7bb7699 100644 --- a/server/src/main/java/server/haengdong/domain/MemberAction.java +++ b/server/src/main/java/server/haengdong/domain/MemberAction.java @@ -30,4 +30,14 @@ public class MemberAction { private MemberActionStatus status; private Long memberGroupId; + + public MemberAction(String memberName, MemberActionStatus status, Long memberGroupId) { + this.memberName = memberName; + this.status = status; + this.memberGroupId = memberGroupId; + } + + public void setAction(Action action) { + this.action = action; + } } diff --git a/server/src/main/java/server/haengdong/domain/MemberActionStatus.java b/server/src/main/java/server/haengdong/domain/MemberActionStatus.java index af7fad121..6172bdb4d 100644 --- a/server/src/main/java/server/haengdong/domain/MemberActionStatus.java +++ b/server/src/main/java/server/haengdong/domain/MemberActionStatus.java @@ -1,7 +1,16 @@ package server.haengdong.domain; +import java.util.Arrays; + public enum MemberActionStatus { IN, OUT, ; + + public static MemberActionStatus of(String status) { + return Arrays.stream(MemberActionStatus.values()) + .filter(s -> s.name().equals(status)) + .findFirst() + .orElseThrow(() -> new IllegalArgumentException("Invalid status: " + status)); + } } diff --git a/server/src/main/java/server/haengdong/domain/MemberGroupIdProvider.java b/server/src/main/java/server/haengdong/domain/MemberGroupIdProvider.java new file mode 100644 index 000000000..c4166e2be --- /dev/null +++ b/server/src/main/java/server/haengdong/domain/MemberGroupIdProvider.java @@ -0,0 +1,11 @@ +package server.haengdong.domain; + +import org.springframework.stereotype.Component; + +@Component +public class MemberGroupIdProvider { + + public Long createGroupId() { + return System.currentTimeMillis(); + } +} diff --git a/server/src/main/java/server/haengdong/persistence/ActionRepository.java b/server/src/main/java/server/haengdong/persistence/ActionRepository.java new file mode 100644 index 000000000..b2447b8d9 --- /dev/null +++ b/server/src/main/java/server/haengdong/persistence/ActionRepository.java @@ -0,0 +1,9 @@ +package server.haengdong.persistence; + +import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.stereotype.Repository; +import server.haengdong.domain.Action; + +@Repository +public interface ActionRepository extends JpaRepository { +} diff --git a/server/src/main/java/server/haengdong/persistence/EventRepository.java b/server/src/main/java/server/haengdong/persistence/EventRepository.java index 855fc80ad..25298a172 100644 --- a/server/src/main/java/server/haengdong/persistence/EventRepository.java +++ b/server/src/main/java/server/haengdong/persistence/EventRepository.java @@ -1,9 +1,11 @@ package server.haengdong.persistence; +import java.util.Optional; import org.springframework.data.jpa.repository.JpaRepository; import org.springframework.stereotype.Repository; import server.haengdong.domain.Event; @Repository public interface EventRepository extends JpaRepository { + Optional findByToken(String token); } diff --git a/server/src/main/java/server/haengdong/persistence/MemberActionRepository.java b/server/src/main/java/server/haengdong/persistence/MemberActionRepository.java new file mode 100644 index 000000000..9e8d96d12 --- /dev/null +++ b/server/src/main/java/server/haengdong/persistence/MemberActionRepository.java @@ -0,0 +1,16 @@ +package server.haengdong.persistence; + +import java.util.List; +import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.data.jpa.repository.Query; +import org.springframework.data.repository.query.Param; +import org.springframework.stereotype.Repository; +import server.haengdong.domain.Event; +import server.haengdong.domain.MemberAction; + +@Repository +public interface MemberActionRepository extends JpaRepository { + + @Query("select m from MemberAction m where m.action.event = :event") + List findAllByEvent(@Param("event") Event event); +} diff --git a/server/src/main/java/server/haengdong/presentation/MemberActionController.java b/server/src/main/java/server/haengdong/presentation/MemberActionController.java new file mode 100644 index 000000000..ce0801a9b --- /dev/null +++ b/server/src/main/java/server/haengdong/presentation/MemberActionController.java @@ -0,0 +1,27 @@ +package server.haengdong.presentation; + +import lombok.RequiredArgsConstructor; +import org.springframework.http.ResponseEntity; +import org.springframework.web.bind.annotation.PathVariable; +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.MemberActionService; +import server.haengdong.presentation.request.MemberActionSaveListRequest; + +@RequiredArgsConstructor +@RestController +public class MemberActionController { + + private final MemberActionService memberActionService; + + @PostMapping("/api/events/{token}/actions/members") + public ResponseEntity saveMemberAction( + @PathVariable("token") String token, + @RequestBody MemberActionSaveListRequest request + ) { + memberActionService.saveMemberAction(token, request.toAppRequest()); + + return ResponseEntity.ok().build(); + } +} diff --git a/server/src/main/java/server/haengdong/presentation/request/MemberActionSaveListRequest.java b/server/src/main/java/server/haengdong/presentation/request/MemberActionSaveListRequest.java new file mode 100644 index 000000000..89eb6ad36 --- /dev/null +++ b/server/src/main/java/server/haengdong/presentation/request/MemberActionSaveListRequest.java @@ -0,0 +1,16 @@ +package server.haengdong.presentation.request; + +import java.util.List; +import server.haengdong.application.request.MemberActionSaveAppRequest; +import server.haengdong.application.request.MemberActionSaveListAppRequest; + +public record MemberActionSaveListRequest(List actions, Long sequence) { + + public MemberActionSaveListAppRequest toAppRequest() { + List appRequests = actions.stream() + .map(MemberActionSaveRequest::toAppRequest) + .toList(); + + return new MemberActionSaveListAppRequest(appRequests, sequence); + } +} diff --git a/server/src/main/java/server/haengdong/presentation/request/MemberActionSaveRequest.java b/server/src/main/java/server/haengdong/presentation/request/MemberActionSaveRequest.java new file mode 100644 index 000000000..a69c51d41 --- /dev/null +++ b/server/src/main/java/server/haengdong/presentation/request/MemberActionSaveRequest.java @@ -0,0 +1,10 @@ +package server.haengdong.presentation.request; + +import server.haengdong.application.request.MemberActionSaveAppRequest; + +public record MemberActionSaveRequest(String name, String status) { + + public MemberActionSaveAppRequest toAppRequest() { + return new MemberActionSaveAppRequest(name, status); + } +} diff --git a/server/src/test/java/server/haengdong/application/MemberActionServiceTest.java b/server/src/test/java/server/haengdong/application/MemberActionServiceTest.java new file mode 100644 index 000000000..075c7f108 --- /dev/null +++ b/server/src/test/java/server/haengdong/application/MemberActionServiceTest.java @@ -0,0 +1,82 @@ +package server.haengdong.application; + +import static org.assertj.core.api.Assertions.assertThatCode; + +import java.util.List; +import org.junit.jupiter.api.AfterEach; +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 server.haengdong.application.request.MemberActionSaveAppRequest; +import server.haengdong.application.request.MemberActionSaveListAppRequest; +import server.haengdong.domain.Action; +import server.haengdong.domain.Event; +import server.haengdong.domain.MemberAction; +import server.haengdong.domain.MemberActionStatus; +import server.haengdong.persistence.ActionRepository; +import server.haengdong.persistence.EventRepository; +import server.haengdong.persistence.MemberActionRepository; + +@SpringBootTest +class MemberActionServiceTest { + + @Autowired + private MemberActionService memberActionService; + + @Autowired + private MemberActionRepository memberActionRepository; + + @Autowired + private EventRepository eventRepository; + + @Autowired + private ActionRepository actionRepository; + + @AfterEach + void tearDown() { + memberActionRepository.deleteAllInBatch(); + actionRepository.deleteAllInBatch(); + eventRepository.deleteAllInBatch(); + } + + @DisplayName("현재 행사에 참여하고 있는 경우에 나갈 수 있다") + @Test + void saveMemberActionTest() { + Event event = eventRepository.save(new Event("test", "TOKEN")); + Action action = actionRepository.save(new Action(event, 1L)); + MemberAction memberAction = new MemberAction("망쵸", MemberActionStatus.IN, 1L); + memberAction.setAction(action); + memberActionRepository.save(memberAction); + + assertThatCode(() -> memberActionService.saveMemberAction("TOKEN", new MemberActionSaveListAppRequest( + List.of(new MemberActionSaveAppRequest("망쵸", "OUT")), 2L))) + .doesNotThrowAnyException(); + } + + @DisplayName("행사에서 퇴장한 경우에 입장할 수 있다") + @Test + void saveMemberActionTest1() { + Event event = eventRepository.save(new Event("test", "TOKEN")); + Action actionOne = actionRepository.save(new Action(event, 1L)); + MemberAction memberActionOne = new MemberAction("망쵸", MemberActionStatus.IN, 1L); + memberActionOne.setAction(actionOne); + memberActionRepository.save(memberActionOne); + Action actionTwo = actionRepository.save(new Action(event, 2L)); + MemberAction memberActionTwo = new MemberAction("망쵸", MemberActionStatus.OUT, 1L); + memberActionTwo.setAction(actionTwo); + memberActionRepository.save(memberActionTwo); + + assertThatCode(() -> memberActionService.saveMemberAction("TOKEN", new MemberActionSaveListAppRequest( + List.of(new MemberActionSaveAppRequest("망쵸", "IN")), 3L))) + .doesNotThrowAnyException(); + } + + @DisplayName("입장하지 않았을 경우 들어올 수 없다") + @Test + void saveMemberActionTest2() { + assertThatCode(() -> memberActionService.saveMemberAction("TOKEN", new MemberActionSaveListAppRequest( + List.of(new MemberActionSaveAppRequest("TOKEN", "OUT")), 1L))) + .isInstanceOf(IllegalArgumentException.class); + } +} diff --git a/server/src/test/java/server/haengdong/presentation/MemberActionControllerTest.java b/server/src/test/java/server/haengdong/presentation/MemberActionControllerTest.java new file mode 100644 index 000000000..fd8d4a7ea --- /dev/null +++ b/server/src/test/java/server/haengdong/presentation/MemberActionControllerTest.java @@ -0,0 +1,51 @@ +package server.haengdong.presentation; + +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 com.fasterxml.jackson.databind.ObjectMapper; +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.autoconfigure.web.servlet.WebMvcTest; +import org.springframework.boot.test.mock.mockito.MockBean; +import org.springframework.http.MediaType; +import org.springframework.test.web.servlet.MockMvc; +import server.haengdong.application.MemberActionService; +import server.haengdong.presentation.request.MemberActionSaveListRequest; +import server.haengdong.presentation.request.MemberActionSaveRequest; + + +@WebMvcTest(MemberActionController.class) +class MemberActionControllerTest { + + @Autowired + private MockMvc mockMvc; + + @Autowired + private ObjectMapper objectMapper; + + @MockBean + private MemberActionService memberActionService; + + @DisplayName("참여자 행동을 추가한다") + @Test + void saveMemberActionTest() throws Exception { + MemberActionSaveListRequest memberActionSaveListRequest = new MemberActionSaveListRequest(List.of( + new MemberActionSaveRequest("망쵸", "IN"), + new MemberActionSaveRequest("이상", "IN"), + new MemberActionSaveRequest("백호", "IN"), + new MemberActionSaveRequest("감자", "IN") + ), 1L); + + String requestBody = objectMapper.writeValueAsString(memberActionSaveListRequest); + + mockMvc.perform(post("/api/events/TOKEN/actions/members") + .contentType(MediaType.APPLICATION_JSON) + .content(requestBody)) + .andDo(print()) + .andExpect(status().isOk()); + } +} From ff15069ef459b69213c3e8de19dd0d81325efad2 Mon Sep 17 00:00:00 2001 From: 3juhwan <13selfesteem91@naver.com> Date: Thu, 18 Jul 2024 22:04:01 +0900 Subject: [PATCH 02/14] =?UTF-8?q?refactor:=20=EB=A9=94=EC=84=9C=EB=93=9C?= =?UTF-8?q?=20=EB=B6=84=EB=A6=AC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: kunsanglee --- .../server/haengdong/application/MemberActionService.java | 7 ++++--- .../main/java/server/haengdong/domain/MemberAction.java | 8 ++++++++ .../java/server/haengdong/domain/MemberActionStatus.java | 8 ++++++++ 3 files changed, 20 insertions(+), 3 deletions(-) diff --git a/server/src/main/java/server/haengdong/application/MemberActionService.java b/server/src/main/java/server/haengdong/application/MemberActionService.java index be3c81ff8..ffc779ee0 100644 --- a/server/src/main/java/server/haengdong/application/MemberActionService.java +++ b/server/src/main/java/server/haengdong/application/MemberActionService.java @@ -57,10 +57,11 @@ private boolean isAvailableAction(List actions, String name, Strin MemberActionStatus memberActionStatus = MemberActionStatus.of(status); for (int i = actions.size() - 1; i >= 0; i--) { MemberAction action = actions.get(i); - if (action.getMemberName().equals(name)) { - return action.getStatus() != memberActionStatus; + if (action.isSameName(name)) { + return action.isAvailable(memberActionStatus); } } - return memberActionStatus == MemberActionStatus.IN; + + return MemberActionStatus.isMemberStatusIn(memberActionStatus); } } diff --git a/server/src/main/java/server/haengdong/domain/MemberAction.java b/server/src/main/java/server/haengdong/domain/MemberAction.java index 4a7bb7699..be4b93d8f 100644 --- a/server/src/main/java/server/haengdong/domain/MemberAction.java +++ b/server/src/main/java/server/haengdong/domain/MemberAction.java @@ -37,6 +37,14 @@ public MemberAction(String memberName, MemberActionStatus status, Long memberGro this.memberGroupId = memberGroupId; } + public boolean isSameName(String name) { + return memberName.equals(name); + } + + public boolean isAvailable(MemberActionStatus memberActionStatus) { + return status.isOpposite(memberActionStatus); + } + public void setAction(Action action) { this.action = action; } diff --git a/server/src/main/java/server/haengdong/domain/MemberActionStatus.java b/server/src/main/java/server/haengdong/domain/MemberActionStatus.java index 6172bdb4d..30a9201fd 100644 --- a/server/src/main/java/server/haengdong/domain/MemberActionStatus.java +++ b/server/src/main/java/server/haengdong/domain/MemberActionStatus.java @@ -13,4 +13,12 @@ public static MemberActionStatus of(String status) { .findFirst() .orElseThrow(() -> new IllegalArgumentException("Invalid status: " + status)); } + + public static boolean isMemberStatusIn(MemberActionStatus memberActionStatus) { + return IN == memberActionStatus; + } + + public boolean isOpposite(MemberActionStatus memberActionStatus) { + return this != memberActionStatus; + } } From e62e2f731541e5e67e3a2d1f07fd1349a83c93d1 Mon Sep 17 00:00:00 2001 From: 3juhwan <13selfesteem91@naver.com> Date: Thu, 18 Jul 2024 22:05:19 +0900 Subject: [PATCH 03/14] =?UTF-8?q?refactor:=20=EC=BD=94=EB=93=9C=20?= =?UTF-8?q?=EC=BB=A8=EB=B2=A4=EC=85=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: kunsanglee --- .../main/java/server/haengdong/application/EventService.java | 2 +- server/src/main/java/server/haengdong/domain/EventStep.java | 2 +- .../server/haengdong/presentation/EventControllerTest.java | 4 ++-- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/server/src/main/java/server/haengdong/application/EventService.java b/server/src/main/java/server/haengdong/application/EventService.java index deac413a4..6a5304e32 100644 --- a/server/src/main/java/server/haengdong/application/EventService.java +++ b/server/src/main/java/server/haengdong/application/EventService.java @@ -20,6 +20,6 @@ public EventAppResponse saveEvent(EventAppRequest request) { Event event = request.toEvent(token); eventRepository.save(event); - return EventAppResponse.of(event); + return EventAppResponse.of(event); } } diff --git a/server/src/main/java/server/haengdong/domain/EventStep.java b/server/src/main/java/server/haengdong/domain/EventStep.java index 741dcaba5..b25035fa5 100644 --- a/server/src/main/java/server/haengdong/domain/EventStep.java +++ b/server/src/main/java/server/haengdong/domain/EventStep.java @@ -21,7 +21,7 @@ public class EventStep { @ManyToOne(fetch = FetchType.LAZY) private Event event; - + private String name; private Long sequence; diff --git a/server/src/test/java/server/haengdong/presentation/EventControllerTest.java b/server/src/test/java/server/haengdong/presentation/EventControllerTest.java index bed814ae3..b60fb6525 100644 --- a/server/src/test/java/server/haengdong/presentation/EventControllerTest.java +++ b/server/src/test/java/server/haengdong/presentation/EventControllerTest.java @@ -42,8 +42,8 @@ void saveEvent() throws Exception { given(eventService.saveEvent(any(EventAppRequest.class))).willReturn(eventAppResponse); mockMvc.perform(post("/api/events") - .contentType(MediaType.APPLICATION_JSON) - .content(requestBody)) + .contentType(MediaType.APPLICATION_JSON) + .content(requestBody)) .andDo(print()) .andExpect(status().isOk()) .andExpect(MockMvcResultMatchers.redirectedUrl("events/" + token)); From ad15f5b1ede5b9f7f16724aba03939b4a93f05fa Mon Sep 17 00:00:00 2001 From: 3juhwan <13selfesteem91@naver.com> Date: Fri, 19 Jul 2024 16:07:18 +0900 Subject: [PATCH 04/14] =?UTF-8?q?refactor:=20=EB=A9=A4=EB=B2=84=20?= =?UTF-8?q?=EC=95=A1=EC=85=98=20=EC=83=9D=EC=84=B1=20=ED=81=B4=EB=9E=98?= =?UTF-8?q?=EC=8A=A4=20=EB=B6=84=EB=A6=AC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: kunsanglee --- .../application/MemberActionService.java | 51 +++------------ .../request/MemberActionSaveAppRequest.java | 5 +- .../MemberActionSaveListAppRequest.java | 10 +-- .../server/haengdong/domain/MemberAction.java | 10 ++- .../haengdong/domain/MemberActionFactory.java | 65 +++++++++++++++++++ .../persistence/ActionRepository.java | 13 ++++ .../request/MemberActionSaveListRequest.java | 4 +- .../application/MemberActionServiceTest.java | 26 ++++---- .../MemberActionControllerTest.java | 3 +- 9 files changed, 110 insertions(+), 77 deletions(-) create mode 100644 server/src/main/java/server/haengdong/domain/MemberActionFactory.java diff --git a/server/src/main/java/server/haengdong/application/MemberActionService.java b/server/src/main/java/server/haengdong/application/MemberActionService.java index ffc779ee0..5e0b607c7 100644 --- a/server/src/main/java/server/haengdong/application/MemberActionService.java +++ b/server/src/main/java/server/haengdong/application/MemberActionService.java @@ -1,67 +1,32 @@ package server.haengdong.application; -import java.util.ArrayList; import java.util.List; -import java.util.stream.IntStream; import lombok.RequiredArgsConstructor; import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; import server.haengdong.application.request.MemberActionSaveListAppRequest; -import server.haengdong.domain.Action; import server.haengdong.domain.Event; import server.haengdong.domain.MemberAction; -import server.haengdong.domain.MemberActionStatus; -import server.haengdong.domain.MemberGroupIdProvider; -import server.haengdong.persistence.ActionRepository; +import server.haengdong.domain.MemberActionFactory; import server.haengdong.persistence.EventRepository; import server.haengdong.persistence.MemberActionRepository; @RequiredArgsConstructor +@Transactional(readOnly = true) @Service public class MemberActionService { private final MemberActionRepository memberActionRepository; private final EventRepository eventRepository; - private final ActionRepository actionRepository; - private final MemberGroupIdProvider memberGroupIdProvider; + private final MemberActionFactory memberActionFactory; + @Transactional public void saveMemberAction(String token, MemberActionSaveListAppRequest request) { Event event = eventRepository.findByToken(token) .orElseThrow(() -> new IllegalArgumentException("event not found")); - List memberActions = memberActionRepository.findAllByEvent(event); - - request.actions().forEach( - action -> { - if (!isAvailableAction(memberActions, action.name(), action.status())) { - throw new IllegalArgumentException(); - } - } - ); - - List actions = new ArrayList<>(); - for (int i = 0; i < memberActions.size(); i++) { - Action action = new Action(event, request.sequence()); - actions.add(actionRepository.save(action)); - } - - Long memberGroupId = memberGroupIdProvider.createGroupId(); - List memberActionList = request.toMemberActionList(memberGroupId); - - IntStream.range(0, memberActionList.size()) - .forEach(i -> memberActionList.get(i).setAction(actions.get(i))); - - memberActionRepository.saveAll(memberActionList); - } - - private boolean isAvailableAction(List actions, String name, String status) { - MemberActionStatus memberActionStatus = MemberActionStatus.of(status); - for (int i = actions.size() - 1; i >= 0; i--) { - MemberAction action = actions.get(i); - if (action.isSameName(name)) { - return action.isAvailable(memberActionStatus); - } - } - - return MemberActionStatus.isMemberStatusIn(memberActionStatus); + List findMemberActions = memberActionRepository.findAllByEvent(event); + List memberActions = memberActionFactory.createMemberActions(request, findMemberActions, event); + memberActionRepository.saveAll(memberActions); } } diff --git a/server/src/main/java/server/haengdong/application/request/MemberActionSaveAppRequest.java b/server/src/main/java/server/haengdong/application/request/MemberActionSaveAppRequest.java index 66310a96e..a7c90efe4 100644 --- a/server/src/main/java/server/haengdong/application/request/MemberActionSaveAppRequest.java +++ b/server/src/main/java/server/haengdong/application/request/MemberActionSaveAppRequest.java @@ -1,11 +1,12 @@ package server.haengdong.application.request; +import server.haengdong.domain.Action; import server.haengdong.domain.MemberAction; import server.haengdong.domain.MemberActionStatus; public record MemberActionSaveAppRequest(String name, String status) { - public MemberAction toMemberAction(Long memberGroupId) { - return new MemberAction(name, MemberActionStatus.of(status), memberGroupId); + public MemberAction toMemberAction(Action action, Long memberGroupId) { + return new MemberAction(action, name, MemberActionStatus.of(status), memberGroupId); } } diff --git a/server/src/main/java/server/haengdong/application/request/MemberActionSaveListAppRequest.java b/server/src/main/java/server/haengdong/application/request/MemberActionSaveListAppRequest.java index 370d57446..f4cc8d44a 100644 --- a/server/src/main/java/server/haengdong/application/request/MemberActionSaveListAppRequest.java +++ b/server/src/main/java/server/haengdong/application/request/MemberActionSaveListAppRequest.java @@ -1,14 +1,6 @@ package server.haengdong.application.request; import java.util.List; -import server.haengdong.domain.MemberAction; -public record MemberActionSaveListAppRequest(List actions, Long sequence) { - - public List toMemberActionList(Long memberGroupId) { - return actions.stream() - .map(action -> action.toMemberAction(memberGroupId)) - .toList(); - - } +public record MemberActionSaveListAppRequest(List actions) { } diff --git a/server/src/main/java/server/haengdong/domain/MemberAction.java b/server/src/main/java/server/haengdong/domain/MemberAction.java index be4b93d8f..b7076bd8c 100644 --- a/server/src/main/java/server/haengdong/domain/MemberAction.java +++ b/server/src/main/java/server/haengdong/domain/MemberAction.java @@ -1,5 +1,6 @@ package server.haengdong.domain; +import jakarta.persistence.CascadeType; import jakarta.persistence.Entity; import jakarta.persistence.EnumType; import jakarta.persistence.Enumerated; @@ -21,7 +22,7 @@ public class MemberAction { @GeneratedValue(strategy = GenerationType.IDENTITY) private Long id; - @OneToOne(fetch = FetchType.LAZY) + @OneToOne(fetch = FetchType.LAZY, cascade = CascadeType.ALL, orphanRemoval = true) private Action action; private String memberName; @@ -31,7 +32,8 @@ public class MemberAction { private Long memberGroupId; - public MemberAction(String memberName, MemberActionStatus status, Long memberGroupId) { + public MemberAction(Action action, String memberName, MemberActionStatus status, Long memberGroupId) { + this.action = action; this.memberName = memberName; this.status = status; this.memberGroupId = memberGroupId; @@ -44,8 +46,4 @@ public boolean isSameName(String name) { public boolean isAvailable(MemberActionStatus memberActionStatus) { return status.isOpposite(memberActionStatus); } - - public void setAction(Action action) { - this.action = action; - } } diff --git a/server/src/main/java/server/haengdong/domain/MemberActionFactory.java b/server/src/main/java/server/haengdong/domain/MemberActionFactory.java new file mode 100644 index 000000000..d9e921d01 --- /dev/null +++ b/server/src/main/java/server/haengdong/domain/MemberActionFactory.java @@ -0,0 +1,65 @@ +package server.haengdong.domain; + +import java.util.ArrayList; +import java.util.List; +import lombok.RequiredArgsConstructor; +import org.springframework.stereotype.Component; +import server.haengdong.application.request.MemberActionSaveAppRequest; +import server.haengdong.application.request.MemberActionSaveListAppRequest; +import server.haengdong.persistence.ActionRepository; + +@RequiredArgsConstructor +@Component +public class MemberActionFactory { + + private final ActionRepository actionRepository; + private final MemberGroupIdProvider memberGroupIdProvider; + + public List createMemberActions( + MemberActionSaveListAppRequest request, + List memberActions, + Event event + ) { + validateActions(request, memberActions); + Long memberGroupId = memberGroupIdProvider.createGroupId(); + long lastSequence = getLastSequence(event); + List memberActionList = new ArrayList<>(); + List actions = request.actions(); + for (MemberActionSaveAppRequest appRequest : actions) { + Action action = new Action(event, ++lastSequence); + MemberAction memberAction = appRequest.toMemberAction(action, memberGroupId); + memberActionList.add(memberAction); + } + return memberActionList; + } + + private void validateActions(MemberActionSaveListAppRequest request, List memberActions) { + for (MemberActionSaveAppRequest action : request.actions()) { + validateAction(memberActions, action); + } + } + + private void validateAction(List memberActions, MemberActionSaveAppRequest action) { + if (!isAvailableAction(memberActions, action.name(), action.status())) { + throw new IllegalArgumentException(); + } + } + + private long getLastSequence(Event event) { + return actionRepository.findLastByEvent(event) + .map(Action::getSequence) + .orElse(0L); + } + + private boolean isAvailableAction(List actions, String name, String status) { + MemberActionStatus memberActionStatus = MemberActionStatus.of(status); + for (int i = actions.size() - 1; i >= 0; i--) { + MemberAction action = actions.get(i); + if (action.isSameName(name)) { + return action.isAvailable(memberActionStatus); + } + } + + return MemberActionStatus.isMemberStatusIn(memberActionStatus); + } +} diff --git a/server/src/main/java/server/haengdong/persistence/ActionRepository.java b/server/src/main/java/server/haengdong/persistence/ActionRepository.java index b2447b8d9..7b7b838d2 100644 --- a/server/src/main/java/server/haengdong/persistence/ActionRepository.java +++ b/server/src/main/java/server/haengdong/persistence/ActionRepository.java @@ -1,9 +1,22 @@ package server.haengdong.persistence; +import java.util.Optional; import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.data.jpa.repository.Query; +import org.springframework.data.repository.query.Param; import org.springframework.stereotype.Repository; import server.haengdong.domain.Action; +import server.haengdong.domain.Event; @Repository public interface ActionRepository extends JpaRepository { + + @Query(""" + SELECT a + FROM Action a + WHERE a.event = :event + ORDER BY a.sequence DESC + LIMIT 1 + """) + Optional findLastByEvent(@Param("event") Event event); } diff --git a/server/src/main/java/server/haengdong/presentation/request/MemberActionSaveListRequest.java b/server/src/main/java/server/haengdong/presentation/request/MemberActionSaveListRequest.java index 89eb6ad36..39a724771 100644 --- a/server/src/main/java/server/haengdong/presentation/request/MemberActionSaveListRequest.java +++ b/server/src/main/java/server/haengdong/presentation/request/MemberActionSaveListRequest.java @@ -4,13 +4,13 @@ import server.haengdong.application.request.MemberActionSaveAppRequest; import server.haengdong.application.request.MemberActionSaveListAppRequest; -public record MemberActionSaveListRequest(List actions, Long sequence) { +public record MemberActionSaveListRequest(List actions) { public MemberActionSaveListAppRequest toAppRequest() { List appRequests = actions.stream() .map(MemberActionSaveRequest::toAppRequest) .toList(); - return new MemberActionSaveListAppRequest(appRequests, sequence); + return new MemberActionSaveListAppRequest(appRequests); } } diff --git a/server/src/test/java/server/haengdong/application/MemberActionServiceTest.java b/server/src/test/java/server/haengdong/application/MemberActionServiceTest.java index 075c7f108..16a9d1553 100644 --- a/server/src/test/java/server/haengdong/application/MemberActionServiceTest.java +++ b/server/src/test/java/server/haengdong/application/MemberActionServiceTest.java @@ -44,13 +44,12 @@ void tearDown() { @Test void saveMemberActionTest() { Event event = eventRepository.save(new Event("test", "TOKEN")); - Action action = actionRepository.save(new Action(event, 1L)); - MemberAction memberAction = new MemberAction("망쵸", MemberActionStatus.IN, 1L); - memberAction.setAction(action); + Action action = new Action(event, 1L); + MemberAction memberAction = new MemberAction(action, "망쵸", MemberActionStatus.IN, 1L); memberActionRepository.save(memberAction); assertThatCode(() -> memberActionService.saveMemberAction("TOKEN", new MemberActionSaveListAppRequest( - List.of(new MemberActionSaveAppRequest("망쵸", "OUT")), 2L))) + List.of(new MemberActionSaveAppRequest("망쵸", "OUT"))))) .doesNotThrowAnyException(); } @@ -58,25 +57,26 @@ void saveMemberActionTest() { @Test void saveMemberActionTest1() { Event event = eventRepository.save(new Event("test", "TOKEN")); - Action actionOne = actionRepository.save(new Action(event, 1L)); - MemberAction memberActionOne = new MemberAction("망쵸", MemberActionStatus.IN, 1L); - memberActionOne.setAction(actionOne); + Action actionOne = new Action(event, 1L); + MemberAction memberActionOne = new MemberAction(actionOne, "망쵸", MemberActionStatus.IN, 1L); memberActionRepository.save(memberActionOne); - Action actionTwo = actionRepository.save(new Action(event, 2L)); - MemberAction memberActionTwo = new MemberAction("망쵸", MemberActionStatus.OUT, 1L); - memberActionTwo.setAction(actionTwo); + + Action actionTwo = new Action(event, 2L); + MemberAction memberActionTwo = new MemberAction(actionTwo, "망쵸", MemberActionStatus.OUT, 1L); memberActionRepository.save(memberActionTwo); assertThatCode(() -> memberActionService.saveMemberAction("TOKEN", new MemberActionSaveListAppRequest( - List.of(new MemberActionSaveAppRequest("망쵸", "IN")), 3L))) + List.of(new MemberActionSaveAppRequest("망쵸", "IN"))))) .doesNotThrowAnyException(); } @DisplayName("입장하지 않았을 경우 들어올 수 없다") @Test void saveMemberActionTest2() { - assertThatCode(() -> memberActionService.saveMemberAction("TOKEN", new MemberActionSaveListAppRequest( - List.of(new MemberActionSaveAppRequest("TOKEN", "OUT")), 1L))) + MemberActionSaveListAppRequest appRequest = new MemberActionSaveListAppRequest( + List.of(new MemberActionSaveAppRequest("TOKEN", "OUT"))); + + assertThatCode(() -> memberActionService.saveMemberAction("TOKEN", appRequest)) .isInstanceOf(IllegalArgumentException.class); } } diff --git a/server/src/test/java/server/haengdong/presentation/MemberActionControllerTest.java b/server/src/test/java/server/haengdong/presentation/MemberActionControllerTest.java index fd8d4a7ea..afdcbaec5 100644 --- a/server/src/test/java/server/haengdong/presentation/MemberActionControllerTest.java +++ b/server/src/test/java/server/haengdong/presentation/MemberActionControllerTest.java @@ -37,8 +37,7 @@ void saveMemberActionTest() throws Exception { new MemberActionSaveRequest("망쵸", "IN"), new MemberActionSaveRequest("이상", "IN"), new MemberActionSaveRequest("백호", "IN"), - new MemberActionSaveRequest("감자", "IN") - ), 1L); + new MemberActionSaveRequest("감자", "IN"))); String requestBody = objectMapper.writeValueAsString(memberActionSaveListRequest); From 14b730c9730a7bfba249020fc54e434209245a32 Mon Sep 17 00:00:00 2001 From: kunsanglee Date: Sat, 20 Jul 2024 15:16:27 +0900 Subject: [PATCH 05/14] =?UTF-8?q?refactor:=20MemberActionFactory=20?= =?UTF-8?q?=EC=BD=94=EB=93=9C=20=EB=A6=AC=ED=8C=A9=ED=84=B0=EB=A7=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../MemberActionFactory.java | 46 +++--- .../application/MemberActionService.java | 19 ++- .../java/server/haengdong/domain/Action.java | 10 ++ .../server/haengdong/domain/MemberAction.java | 8 +- .../application/MemberActionFactoryTest.java | 147 ++++++++++++++++++ .../application/MemberActionServiceTest.java | 10 +- 6 files changed, 204 insertions(+), 36 deletions(-) rename server/src/main/java/server/haengdong/{domain => application}/MemberActionFactory.java (53%) create mode 100644 server/src/test/java/server/haengdong/application/MemberActionFactoryTest.java diff --git a/server/src/main/java/server/haengdong/domain/MemberActionFactory.java b/server/src/main/java/server/haengdong/application/MemberActionFactory.java similarity index 53% rename from server/src/main/java/server/haengdong/domain/MemberActionFactory.java rename to server/src/main/java/server/haengdong/application/MemberActionFactory.java index d9e921d01..85b3cbac3 100644 --- a/server/src/main/java/server/haengdong/domain/MemberActionFactory.java +++ b/server/src/main/java/server/haengdong/application/MemberActionFactory.java @@ -1,65 +1,63 @@ -package server.haengdong.domain; +package server.haengdong.application; import java.util.ArrayList; +import java.util.Comparator; import java.util.List; import lombok.RequiredArgsConstructor; import org.springframework.stereotype.Component; import server.haengdong.application.request.MemberActionSaveAppRequest; -import server.haengdong.application.request.MemberActionSaveListAppRequest; -import server.haengdong.persistence.ActionRepository; +import server.haengdong.application.request.MemberActionsSaveAppRequest; +import server.haengdong.domain.Action; +import server.haengdong.domain.MemberAction; +import server.haengdong.domain.MemberActionStatus; +import server.haengdong.domain.MemberGroupIdProvider; @RequiredArgsConstructor @Component public class MemberActionFactory { - private final ActionRepository actionRepository; private final MemberGroupIdProvider memberGroupIdProvider; public List createMemberActions( - MemberActionSaveListAppRequest request, + MemberActionsSaveAppRequest request, List memberActions, - Event event + Action action ) { + memberActions.sort(Comparator.comparing(MemberAction::getSequence)); validateActions(request, memberActions); + Long memberGroupId = memberGroupIdProvider.createGroupId(); - long lastSequence = getLastSequence(event); - List memberActionList = new ArrayList<>(); + List createdMemberActions = new ArrayList<>(); List actions = request.actions(); for (MemberActionSaveAppRequest appRequest : actions) { - Action action = new Action(event, ++lastSequence); MemberAction memberAction = appRequest.toMemberAction(action, memberGroupId); - memberActionList.add(memberAction); + createdMemberActions.add(memberAction); + action = action.next(); } - return memberActionList; + + return createdMemberActions; } - private void validateActions(MemberActionSaveListAppRequest request, List memberActions) { + private void validateActions(MemberActionsSaveAppRequest request, List memberActions) { for (MemberActionSaveAppRequest action : request.actions()) { validateAction(memberActions, action); } } private void validateAction(List memberActions, MemberActionSaveAppRequest action) { - if (!isAvailableAction(memberActions, action.name(), action.status())) { + MemberActionStatus memberActionStatus = MemberActionStatus.of(action.status()); + if (isInvalidStatus(memberActions, action.name(), memberActionStatus)) { throw new IllegalArgumentException(); } } - private long getLastSequence(Event event) { - return actionRepository.findLastByEvent(event) - .map(Action::getSequence) - .orElse(0L); - } - - private boolean isAvailableAction(List actions, String name, String status) { - MemberActionStatus memberActionStatus = MemberActionStatus.of(status); + private boolean isInvalidStatus(List actions, String name, MemberActionStatus status) { for (int i = actions.size() - 1; i >= 0; i--) { MemberAction action = actions.get(i); if (action.isSameName(name)) { - return action.isAvailable(memberActionStatus); + return action.isSameStatus(status); } } - - return MemberActionStatus.isMemberStatusIn(memberActionStatus); + return MemberActionStatus.IN != status; } } diff --git a/server/src/main/java/server/haengdong/application/MemberActionService.java b/server/src/main/java/server/haengdong/application/MemberActionService.java index 5e0b607c7..491981b06 100644 --- a/server/src/main/java/server/haengdong/application/MemberActionService.java +++ b/server/src/main/java/server/haengdong/application/MemberActionService.java @@ -4,10 +4,11 @@ import lombok.RequiredArgsConstructor; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; -import server.haengdong.application.request.MemberActionSaveListAppRequest; +import server.haengdong.application.request.MemberActionsSaveAppRequest; +import server.haengdong.domain.Action; import server.haengdong.domain.Event; import server.haengdong.domain.MemberAction; -import server.haengdong.domain.MemberActionFactory; +import server.haengdong.persistence.ActionRepository; import server.haengdong.persistence.EventRepository; import server.haengdong.persistence.MemberActionRepository; @@ -16,17 +17,25 @@ @Service public class MemberActionService { + private final MemberActionFactory memberActionFactory; private final MemberActionRepository memberActionRepository; private final EventRepository eventRepository; - private final MemberActionFactory memberActionFactory; + private final ActionRepository actionRepository; @Transactional - public void saveMemberAction(String token, MemberActionSaveListAppRequest request) { + public void saveMemberAction(String token, MemberActionsSaveAppRequest request) { Event event = eventRepository.findByToken(token) .orElseThrow(() -> new IllegalArgumentException("event not found")); List findMemberActions = memberActionRepository.findAllByEvent(event); - List memberActions = memberActionFactory.createMemberActions(request, findMemberActions, event); + Action action = createStartAction(event); + List memberActions = memberActionFactory.createMemberActions(request, findMemberActions, action); memberActionRepository.saveAll(memberActions); } + + private Action createStartAction(Event event) { + return actionRepository.findLastByEvent(event) + .map(Action::next) + .orElse(Action.createFirst(event)); + } } diff --git a/server/src/main/java/server/haengdong/domain/Action.java b/server/src/main/java/server/haengdong/domain/Action.java index 7a47b1de5..be294dac3 100644 --- a/server/src/main/java/server/haengdong/domain/Action.java +++ b/server/src/main/java/server/haengdong/domain/Action.java @@ -15,6 +15,8 @@ @Entity public class Action { + private static final long FIRST_SEQUENCE = 1L; + @Id @GeneratedValue(strategy = GenerationType.IDENTITY) private Long id; @@ -28,4 +30,12 @@ public Action(Event event, Long sequence) { this.event = event; this.sequence = sequence; } + + public static Action createFirst(Event event) { + return new Action(event, FIRST_SEQUENCE); + } + + public Action next() { + return new Action(event, sequence + 1); + } } diff --git a/server/src/main/java/server/haengdong/domain/MemberAction.java b/server/src/main/java/server/haengdong/domain/MemberAction.java index b7076bd8c..eb8d8fdec 100644 --- a/server/src/main/java/server/haengdong/domain/MemberAction.java +++ b/server/src/main/java/server/haengdong/domain/MemberAction.java @@ -43,7 +43,11 @@ public boolean isSameName(String name) { return memberName.equals(name); } - public boolean isAvailable(MemberActionStatus memberActionStatus) { - return status.isOpposite(memberActionStatus); + public boolean isSameStatus(MemberActionStatus memberActionStatus) { + return status == memberActionStatus; + } + + public Long getSequence() { + return action.getSequence(); } } diff --git a/server/src/test/java/server/haengdong/application/MemberActionFactoryTest.java b/server/src/test/java/server/haengdong/application/MemberActionFactoryTest.java new file mode 100644 index 000000000..764caee91 --- /dev/null +++ b/server/src/test/java/server/haengdong/application/MemberActionFactoryTest.java @@ -0,0 +1,147 @@ +package server.haengdong.application; + +import static org.assertj.core.api.Assertions.assertThatCode; +import static org.assertj.core.api.Assertions.assertThatThrownBy; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; +import org.junit.jupiter.api.AfterEach; +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 server.haengdong.application.request.MemberActionSaveAppRequest; +import server.haengdong.application.request.MemberActionsSaveAppRequest; +import server.haengdong.domain.Action; +import server.haengdong.domain.Event; +import server.haengdong.domain.MemberAction; +import server.haengdong.domain.MemberActionStatus; +import server.haengdong.persistence.ActionRepository; +import server.haengdong.persistence.EventRepository; +import server.haengdong.persistence.MemberActionRepository; + +@SpringBootTest +class MemberActionFactoryTest { + + @Autowired + private MemberActionFactory memberActionFactory; + + @Autowired + private MemberActionRepository memberActionRepository; + + @Autowired + private ActionRepository actionRepository; + + @Autowired + private EventRepository eventRepository; + + @AfterEach + void tearDown() { + memberActionRepository.deleteAllInBatch(); + actionRepository.deleteAllInBatch(); + eventRepository.deleteAllInBatch(); + } + + @DisplayName("액션 ID를 기준으로 정렬한 상태로 새로운 멤버 액션 요청을 검증한다.") + @Test + void createMemberActionsTest() { + Event event = eventRepository.save(new Event("우당탕탕 행동대장 백엔드 회식", "토다리_토큰")); + Action action1 = new Action(event, 1L); + Action action2 = new Action(event, 2L); + MemberAction memberAction1 = new MemberAction(action1, "토다리", MemberActionStatus.IN, 1L); + MemberAction memberAction2 = new MemberAction(action2, "토다리", MemberActionStatus.OUT, 2L); + memberActionRepository.saveAll(List.of(memberAction1, memberAction2)); + + MemberActionsSaveAppRequest request = new MemberActionsSaveAppRequest( + List.of(new MemberActionSaveAppRequest("토다리", "OUT"))); + List unorderedMemberActions = Arrays.asList(memberAction2, memberAction1); + Action startAction = new Action(event, 3L); + + assertThatThrownBy( + () -> memberActionFactory.createMemberActions(request, unorderedMemberActions, startAction)) + .isInstanceOf(IllegalArgumentException.class); + } + + @DisplayName("현재 행사에 참여 중인 경우에 퇴장할 수 있다.") + @Test + void createMemberActionsTest1() { + Event event = eventRepository.save(new Event("test", "TOKEN")); + Action action = new Action(event, 1L); + MemberAction memberAction = new MemberAction(action, "토다리", MemberActionStatus.IN, 1L); + memberActionRepository.save(memberAction); + + MemberActionsSaveAppRequest request = new MemberActionsSaveAppRequest( + List.of(new MemberActionSaveAppRequest("토다리", "OUT"))); + Action startAction = new Action(event, 2L); + + assertThatCode(() -> memberActionFactory.createMemberActions(request, Arrays.asList(memberAction), startAction)) + .doesNotThrowAnyException(); + } + + @DisplayName("행사에서 퇴장한 경우에 입장할 수 있다.") + @Test + void createMemberActionsTest2() { + Event event = eventRepository.save(new Event("test", "TOKEN")); + Action action1 = new Action(event, 1L); + MemberAction memberAction1 = new MemberAction(action1, "토다리", MemberActionStatus.IN, 1L); + memberActionRepository.save(memberAction1); + Action action2 = new Action(event, 2L); + MemberAction memberAction2 = new MemberAction(action2, "토다리", MemberActionStatus.OUT, 2L); + memberActionRepository.save(memberAction2); + + MemberActionsSaveAppRequest request = new MemberActionsSaveAppRequest( + List.of(new MemberActionSaveAppRequest("토다리", "IN"))); + Action startAction = new Action(event, 3L); + + assertThatCode( + () -> memberActionFactory.createMemberActions(request, Arrays.asList(memberAction1, memberAction2), + startAction)) + .doesNotThrowAnyException(); + } + + @DisplayName("행사에 입장한 적 없는 경우에 입장할 수 있다.") + @Test + void createMemberActionsTest3() { + Event event = eventRepository.save(new Event("test", "TOKEN")); + Action action = new Action(event, 1L); + MemberAction memberAction = new MemberAction(action, "토다리", MemberActionStatus.IN, 1L); + memberActionRepository.save(memberAction); + + MemberActionsSaveAppRequest request = new MemberActionsSaveAppRequest( + List.of(new MemberActionSaveAppRequest("쿠키", "IN"))); + Action startAction = new Action(event, 2L); + + assertThatCode(() -> memberActionFactory.createMemberActions(request, Arrays.asList(memberAction), startAction)) + .doesNotThrowAnyException(); + } + + @DisplayName("행사에 입장하지 않았을 경우 퇴장할 수 없다.") + @Test + void createMemberActionTest4() { + Event event = eventRepository.save(new Event("test", "TOKEN")); + + MemberActionsSaveAppRequest request = new MemberActionsSaveAppRequest( + List.of(new MemberActionSaveAppRequest("쿠키", "OUT"))); + Action startAction = new Action(event, 2L); + + assertThatCode(() -> memberActionFactory.createMemberActions(request, new ArrayList<>(), startAction)) + .isInstanceOf(IllegalArgumentException.class); + } + + @DisplayName("행사에 이미 참여 중인 경우 다시 입장할 수 없다.") + @Test + void createMemberActionTest5() { + Event event = eventRepository.save(new Event("test", "TOKEN")); + Action action = new Action(event, 1L); + MemberAction memberAction = new MemberAction(action, "쿠키", MemberActionStatus.IN, 1L); + memberActionRepository.save(memberAction); + + MemberActionsSaveAppRequest request = new MemberActionsSaveAppRequest( + List.of(new MemberActionSaveAppRequest("쿠키", "IN"))); + Action startAction = new Action(event, 2L); + + assertThatCode(() -> memberActionFactory.createMemberActions(request, Arrays.asList(memberAction), startAction)) + .isInstanceOf(IllegalArgumentException.class); + } +} diff --git a/server/src/test/java/server/haengdong/application/MemberActionServiceTest.java b/server/src/test/java/server/haengdong/application/MemberActionServiceTest.java index 16a9d1553..73a7c3d9d 100644 --- a/server/src/test/java/server/haengdong/application/MemberActionServiceTest.java +++ b/server/src/test/java/server/haengdong/application/MemberActionServiceTest.java @@ -9,7 +9,7 @@ import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.test.context.SpringBootTest; import server.haengdong.application.request.MemberActionSaveAppRequest; -import server.haengdong.application.request.MemberActionSaveListAppRequest; +import server.haengdong.application.request.MemberActionsSaveAppRequest; import server.haengdong.domain.Action; import server.haengdong.domain.Event; import server.haengdong.domain.MemberAction; @@ -48,7 +48,7 @@ void saveMemberActionTest() { MemberAction memberAction = new MemberAction(action, "망쵸", MemberActionStatus.IN, 1L); memberActionRepository.save(memberAction); - assertThatCode(() -> memberActionService.saveMemberAction("TOKEN", new MemberActionSaveListAppRequest( + assertThatCode(() -> memberActionService.saveMemberAction("TOKEN", new MemberActionsSaveAppRequest( List.of(new MemberActionSaveAppRequest("망쵸", "OUT"))))) .doesNotThrowAnyException(); } @@ -65,15 +65,15 @@ void saveMemberActionTest1() { MemberAction memberActionTwo = new MemberAction(actionTwo, "망쵸", MemberActionStatus.OUT, 1L); memberActionRepository.save(memberActionTwo); - assertThatCode(() -> memberActionService.saveMemberAction("TOKEN", new MemberActionSaveListAppRequest( + assertThatCode(() -> memberActionService.saveMemberAction("TOKEN", new MemberActionsSaveAppRequest( List.of(new MemberActionSaveAppRequest("망쵸", "IN"))))) .doesNotThrowAnyException(); } - @DisplayName("입장하지 않았을 경우 들어올 수 없다") + @DisplayName("행사에 입장하지 않았을 경우 퇴장할 수 없다") @Test void saveMemberActionTest2() { - MemberActionSaveListAppRequest appRequest = new MemberActionSaveListAppRequest( + MemberActionsSaveAppRequest appRequest = new MemberActionsSaveAppRequest( List.of(new MemberActionSaveAppRequest("TOKEN", "OUT"))); assertThatCode(() -> memberActionService.saveMemberAction("TOKEN", appRequest)) From a6c7b70ec3a372b3950e043bd68ea3df62854db1 Mon Sep 17 00:00:00 2001 From: kunsanglee Date: Sat, 20 Jul 2024 15:16:50 +0900 Subject: [PATCH 06/14] =?UTF-8?q?refactor:=20DTO=20=ED=81=B4=EB=9E=98?= =?UTF-8?q?=EC=8A=A4=EB=AA=85=20=EB=A6=AC=ED=8C=A9=ED=84=B0=EB=A7=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../MemberActionSaveListAppRequest.java | 6 ------ .../request/MemberActionsSaveAppRequest.java | 6 ++++++ .../presentation/MemberActionController.java | 4 ++-- ...est.java => MemberActionsSaveRequest.java} | 8 +++---- .../presentation/EventControllerTest.java | 8 +++---- .../MemberActionControllerTest.java | 21 +++++++++---------- 6 files changed, 26 insertions(+), 27 deletions(-) delete mode 100644 server/src/main/java/server/haengdong/application/request/MemberActionSaveListAppRequest.java create mode 100644 server/src/main/java/server/haengdong/application/request/MemberActionsSaveAppRequest.java rename server/src/main/java/server/haengdong/presentation/request/{MemberActionSaveListRequest.java => MemberActionsSaveRequest.java} (52%) diff --git a/server/src/main/java/server/haengdong/application/request/MemberActionSaveListAppRequest.java b/server/src/main/java/server/haengdong/application/request/MemberActionSaveListAppRequest.java deleted file mode 100644 index f4cc8d44a..000000000 --- a/server/src/main/java/server/haengdong/application/request/MemberActionSaveListAppRequest.java +++ /dev/null @@ -1,6 +0,0 @@ -package server.haengdong.application.request; - -import java.util.List; - -public record MemberActionSaveListAppRequest(List actions) { -} diff --git a/server/src/main/java/server/haengdong/application/request/MemberActionsSaveAppRequest.java b/server/src/main/java/server/haengdong/application/request/MemberActionsSaveAppRequest.java new file mode 100644 index 000000000..650b908df --- /dev/null +++ b/server/src/main/java/server/haengdong/application/request/MemberActionsSaveAppRequest.java @@ -0,0 +1,6 @@ +package server.haengdong.application.request; + +import java.util.List; + +public record MemberActionsSaveAppRequest(List actions) { +} diff --git a/server/src/main/java/server/haengdong/presentation/MemberActionController.java b/server/src/main/java/server/haengdong/presentation/MemberActionController.java index ce0801a9b..e35bcfd7b 100644 --- a/server/src/main/java/server/haengdong/presentation/MemberActionController.java +++ b/server/src/main/java/server/haengdong/presentation/MemberActionController.java @@ -7,7 +7,7 @@ import org.springframework.web.bind.annotation.RequestBody; import org.springframework.web.bind.annotation.RestController; import server.haengdong.application.MemberActionService; -import server.haengdong.presentation.request.MemberActionSaveListRequest; +import server.haengdong.presentation.request.MemberActionsSaveRequest; @RequiredArgsConstructor @RestController @@ -18,7 +18,7 @@ public class MemberActionController { @PostMapping("/api/events/{token}/actions/members") public ResponseEntity saveMemberAction( @PathVariable("token") String token, - @RequestBody MemberActionSaveListRequest request + @RequestBody MemberActionsSaveRequest request ) { memberActionService.saveMemberAction(token, request.toAppRequest()); diff --git a/server/src/main/java/server/haengdong/presentation/request/MemberActionSaveListRequest.java b/server/src/main/java/server/haengdong/presentation/request/MemberActionsSaveRequest.java similarity index 52% rename from server/src/main/java/server/haengdong/presentation/request/MemberActionSaveListRequest.java rename to server/src/main/java/server/haengdong/presentation/request/MemberActionsSaveRequest.java index 39a724771..bfe80f0ee 100644 --- a/server/src/main/java/server/haengdong/presentation/request/MemberActionSaveListRequest.java +++ b/server/src/main/java/server/haengdong/presentation/request/MemberActionsSaveRequest.java @@ -2,15 +2,15 @@ import java.util.List; import server.haengdong.application.request.MemberActionSaveAppRequest; -import server.haengdong.application.request.MemberActionSaveListAppRequest; +import server.haengdong.application.request.MemberActionsSaveAppRequest; -public record MemberActionSaveListRequest(List actions) { +public record MemberActionsSaveRequest(List actions) { - public MemberActionSaveListAppRequest toAppRequest() { + public MemberActionsSaveAppRequest toAppRequest() { List appRequests = actions.stream() .map(MemberActionSaveRequest::toAppRequest) .toList(); - return new MemberActionSaveListAppRequest(appRequests); + return new MemberActionsSaveAppRequest(appRequests); } } diff --git a/server/src/test/java/server/haengdong/presentation/EventControllerTest.java b/server/src/test/java/server/haengdong/presentation/EventControllerTest.java index b60fb6525..a1d67f0a1 100644 --- a/server/src/test/java/server/haengdong/presentation/EventControllerTest.java +++ b/server/src/test/java/server/haengdong/presentation/EventControllerTest.java @@ -32,18 +32,18 @@ class EventControllerTest { @MockBean private EventService eventService; - @DisplayName("이벤트를 생성한다") + @DisplayName("이벤트를 생성한다.") @Test void saveEvent() throws Exception { - EventSaveRequest eventSaveRequest = new EventSaveRequest("test"); + EventSaveRequest eventSaveRequest = new EventSaveRequest("토다리"); String requestBody = objectMapper.writeValueAsString(eventSaveRequest); String token = "TOKEN"; EventAppResponse eventAppResponse = new EventAppResponse(token); given(eventService.saveEvent(any(EventAppRequest.class))).willReturn(eventAppResponse); mockMvc.perform(post("/api/events") - .contentType(MediaType.APPLICATION_JSON) - .content(requestBody)) + .contentType(MediaType.APPLICATION_JSON) + .content(requestBody)) .andDo(print()) .andExpect(status().isOk()) .andExpect(MockMvcResultMatchers.redirectedUrl("events/" + token)); diff --git a/server/src/test/java/server/haengdong/presentation/MemberActionControllerTest.java b/server/src/test/java/server/haengdong/presentation/MemberActionControllerTest.java index afdcbaec5..8f9e71182 100644 --- a/server/src/test/java/server/haengdong/presentation/MemberActionControllerTest.java +++ b/server/src/test/java/server/haengdong/presentation/MemberActionControllerTest.java @@ -14,9 +14,8 @@ import org.springframework.http.MediaType; import org.springframework.test.web.servlet.MockMvc; import server.haengdong.application.MemberActionService; -import server.haengdong.presentation.request.MemberActionSaveListRequest; import server.haengdong.presentation.request.MemberActionSaveRequest; - +import server.haengdong.presentation.request.MemberActionsSaveRequest; @WebMvcTest(MemberActionController.class) class MemberActionControllerTest { @@ -30,20 +29,20 @@ class MemberActionControllerTest { @MockBean private MemberActionService memberActionService; - @DisplayName("참여자 행동을 추가한다") + @DisplayName("참여자 행동을 추가한다.") @Test void saveMemberActionTest() throws Exception { - MemberActionSaveListRequest memberActionSaveListRequest = new MemberActionSaveListRequest(List.of( - new MemberActionSaveRequest("망쵸", "IN"), - new MemberActionSaveRequest("이상", "IN"), - new MemberActionSaveRequest("백호", "IN"), - new MemberActionSaveRequest("감자", "IN"))); + MemberActionsSaveRequest memberActionsSaveRequest = new MemberActionsSaveRequest(List.of( + new MemberActionSaveRequest("웨디", "IN"), + new MemberActionSaveRequest("소하", "IN"), + new MemberActionSaveRequest("토다리", "IN"), + new MemberActionSaveRequest("쿠키", "IN"))); - String requestBody = objectMapper.writeValueAsString(memberActionSaveListRequest); + String requestBody = objectMapper.writeValueAsString(memberActionsSaveRequest); mockMvc.perform(post("/api/events/TOKEN/actions/members") - .contentType(MediaType.APPLICATION_JSON) - .content(requestBody)) + .contentType(MediaType.APPLICATION_JSON) + .content(requestBody)) .andDo(print()) .andExpect(status().isOk()); } From db16486e4011d932ade945de74bf3a61f6c1758a Mon Sep 17 00:00:00 2001 From: kunsanglee Date: Sat, 20 Jul 2024 15:23:55 +0900 Subject: [PATCH 07/14] =?UTF-8?q?refactor:=20MemberActionRepository=20Lazy?= =?UTF-8?q?=20Loading=20=EC=A0=81=EC=9A=A9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../server/haengdong/persistence/MemberActionRepository.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/server/src/main/java/server/haengdong/persistence/MemberActionRepository.java b/server/src/main/java/server/haengdong/persistence/MemberActionRepository.java index 9e8d96d12..97d06618b 100644 --- a/server/src/main/java/server/haengdong/persistence/MemberActionRepository.java +++ b/server/src/main/java/server/haengdong/persistence/MemberActionRepository.java @@ -11,6 +11,6 @@ @Repository public interface MemberActionRepository extends JpaRepository { - @Query("select m from MemberAction m where m.action.event = :event") + @Query("select m from MemberAction m join fetch m.action where m.action.event = :event") List findAllByEvent(@Param("event") Event event); } From 9cec9feafd8c73c3fdaad2205aee385c90e1dc27 Mon Sep 17 00:00:00 2001 From: kunsanglee Date: Sat, 20 Jul 2024 23:38:30 +0900 Subject: [PATCH 08/14] =?UTF-8?q?test:=20MemberActionFactory=20createMembe?= =?UTF-8?q?rActions=20=EA=B2=B0=EA=B3=BC=20=EA=B2=80=EC=A6=9D=20=ED=85=8C?= =?UTF-8?q?=EC=8A=A4=ED=8A=B8=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../application/MemberActionFactoryTest.java | 33 ++++++++++++++++--- 1 file changed, 28 insertions(+), 5 deletions(-) diff --git a/server/src/test/java/server/haengdong/application/MemberActionFactoryTest.java b/server/src/test/java/server/haengdong/application/MemberActionFactoryTest.java index 764caee91..d00a0d8fe 100644 --- a/server/src/test/java/server/haengdong/application/MemberActionFactoryTest.java +++ b/server/src/test/java/server/haengdong/application/MemberActionFactoryTest.java @@ -1,7 +1,9 @@ package server.haengdong.application; +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.assertj.core.api.Assertions.tuple; import java.util.ArrayList; import java.util.Arrays; @@ -63,9 +65,30 @@ void createMemberActionsTest() { .isInstanceOf(IllegalArgumentException.class); } - @DisplayName("현재 행사에 참여 중인 경우에 퇴장할 수 있다.") + @DisplayName("인원 변동 액션을 생성한다.") @Test void createMemberActionsTest1() { + Event event = eventRepository.save(new Event("우당탕탕 행동대장 백엔드 회식", "토다리_토큰")); + Action action = new Action(event, 1L); + MemberAction memberAction = new MemberAction(action, "토다리", MemberActionStatus.IN, 1L); + memberActionRepository.save(memberAction); + + MemberActionsSaveAppRequest memberActionsSaveAppRequest = new MemberActionsSaveAppRequest( + List.of(new MemberActionSaveAppRequest("토다리", "OUT"))); + + List memberActions = memberActionFactory.createMemberActions(memberActionsSaveAppRequest, + Arrays.asList(memberAction), action); + + assertThat(memberActions).hasSize(1) + .extracting("action", "memberName", "status") + .containsExactly( + tuple(action, "토다리", MemberActionStatus.OUT) + ); + } + + @DisplayName("현재 행사에 참여 중인 경우에 퇴장할 수 있다.") + @Test + void createMemberActionsTest2() { Event event = eventRepository.save(new Event("test", "TOKEN")); Action action = new Action(event, 1L); MemberAction memberAction = new MemberAction(action, "토다리", MemberActionStatus.IN, 1L); @@ -81,7 +104,7 @@ void createMemberActionsTest1() { @DisplayName("행사에서 퇴장한 경우에 입장할 수 있다.") @Test - void createMemberActionsTest2() { + void createMemberActionsTest3() { Event event = eventRepository.save(new Event("test", "TOKEN")); Action action1 = new Action(event, 1L); MemberAction memberAction1 = new MemberAction(action1, "토다리", MemberActionStatus.IN, 1L); @@ -102,7 +125,7 @@ void createMemberActionsTest2() { @DisplayName("행사에 입장한 적 없는 경우에 입장할 수 있다.") @Test - void createMemberActionsTest3() { + void createMemberActionsTest4() { Event event = eventRepository.save(new Event("test", "TOKEN")); Action action = new Action(event, 1L); MemberAction memberAction = new MemberAction(action, "토다리", MemberActionStatus.IN, 1L); @@ -118,7 +141,7 @@ void createMemberActionsTest3() { @DisplayName("행사에 입장하지 않았을 경우 퇴장할 수 없다.") @Test - void createMemberActionTest4() { + void createMemberActionTest5() { Event event = eventRepository.save(new Event("test", "TOKEN")); MemberActionsSaveAppRequest request = new MemberActionsSaveAppRequest( @@ -131,7 +154,7 @@ void createMemberActionTest4() { @DisplayName("행사에 이미 참여 중인 경우 다시 입장할 수 없다.") @Test - void createMemberActionTest5() { + void createMemberActionTest6() { Event event = eventRepository.save(new Event("test", "TOKEN")); Action action = new Action(event, 1L); MemberAction memberAction = new MemberAction(action, "쿠키", MemberActionStatus.IN, 1L); From 008f5019af97d907734f514b473461351aa911e8 Mon Sep 17 00:00:00 2001 From: 3juhwan <13selfesteem91@naver.com> Date: Sun, 21 Jul 2024 14:18:08 +0900 Subject: [PATCH 09/14] =?UTF-8?q?refactor:=20=EC=BB=A8=EB=B2=A4=EC=85=98?= =?UTF-8?q?=EC=97=90=20=EB=A7=9E=EA=B2=8C=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: kunsanglee --- .../haengdong/application/MemberActionFactory.java | 8 ++++---- .../server/haengdong/domain/MemberActionStatus.java | 8 -------- .../application/MemberActionFactoryTest.java | 13 ++++++------- 3 files changed, 10 insertions(+), 19 deletions(-) diff --git a/server/src/main/java/server/haengdong/application/MemberActionFactory.java b/server/src/main/java/server/haengdong/application/MemberActionFactory.java index 85b3cbac3..a0969a367 100644 --- a/server/src/main/java/server/haengdong/application/MemberActionFactory.java +++ b/server/src/main/java/server/haengdong/application/MemberActionFactory.java @@ -40,13 +40,13 @@ public List createMemberActions( private void validateActions(MemberActionsSaveAppRequest request, List memberActions) { for (MemberActionSaveAppRequest action : request.actions()) { - validateAction(memberActions, action); + validateAction(action, memberActions); } } - private void validateAction(List memberActions, MemberActionSaveAppRequest action) { - MemberActionStatus memberActionStatus = MemberActionStatus.of(action.status()); - if (isInvalidStatus(memberActions, action.name(), memberActionStatus)) { + private void validateAction(MemberActionSaveAppRequest request, List memberActions) { + MemberActionStatus memberActionStatus = MemberActionStatus.of(request.status()); + if (isInvalidStatus(memberActions, request.name(), memberActionStatus)) { throw new IllegalArgumentException(); } } diff --git a/server/src/main/java/server/haengdong/domain/MemberActionStatus.java b/server/src/main/java/server/haengdong/domain/MemberActionStatus.java index 30a9201fd..6172bdb4d 100644 --- a/server/src/main/java/server/haengdong/domain/MemberActionStatus.java +++ b/server/src/main/java/server/haengdong/domain/MemberActionStatus.java @@ -13,12 +13,4 @@ public static MemberActionStatus of(String status) { .findFirst() .orElseThrow(() -> new IllegalArgumentException("Invalid status: " + status)); } - - public static boolean isMemberStatusIn(MemberActionStatus memberActionStatus) { - return IN == memberActionStatus; - } - - public boolean isOpposite(MemberActionStatus memberActionStatus) { - return this != memberActionStatus; - } } diff --git a/server/src/test/java/server/haengdong/application/MemberActionFactoryTest.java b/server/src/test/java/server/haengdong/application/MemberActionFactoryTest.java index d00a0d8fe..b5d5d116e 100644 --- a/server/src/test/java/server/haengdong/application/MemberActionFactoryTest.java +++ b/server/src/test/java/server/haengdong/application/MemberActionFactoryTest.java @@ -60,8 +60,7 @@ void createMemberActionsTest() { List unorderedMemberActions = Arrays.asList(memberAction2, memberAction1); Action startAction = new Action(event, 3L); - assertThatThrownBy( - () -> memberActionFactory.createMemberActions(request, unorderedMemberActions, startAction)) + assertThatThrownBy(() -> memberActionFactory.createMemberActions(request, unorderedMemberActions, startAction)) .isInstanceOf(IllegalArgumentException.class); } @@ -77,7 +76,7 @@ void createMemberActionsTest1() { List.of(new MemberActionSaveAppRequest("토다리", "OUT"))); List memberActions = memberActionFactory.createMemberActions(memberActionsSaveAppRequest, - Arrays.asList(memberAction), action); + List.of(memberAction), action); assertThat(memberActions).hasSize(1) .extracting("action", "memberName", "status") @@ -98,7 +97,7 @@ void createMemberActionsTest2() { List.of(new MemberActionSaveAppRequest("토다리", "OUT"))); Action startAction = new Action(event, 2L); - assertThatCode(() -> memberActionFactory.createMemberActions(request, Arrays.asList(memberAction), startAction)) + assertThatCode(() -> memberActionFactory.createMemberActions(request, List.of(memberAction), startAction)) .doesNotThrowAnyException(); } @@ -119,7 +118,7 @@ void createMemberActionsTest3() { assertThatCode( () -> memberActionFactory.createMemberActions(request, Arrays.asList(memberAction1, memberAction2), - startAction)) + startAction)) .doesNotThrowAnyException(); } @@ -135,7 +134,7 @@ void createMemberActionsTest4() { List.of(new MemberActionSaveAppRequest("쿠키", "IN"))); Action startAction = new Action(event, 2L); - assertThatCode(() -> memberActionFactory.createMemberActions(request, Arrays.asList(memberAction), startAction)) + assertThatCode(() -> memberActionFactory.createMemberActions(request, List.of(memberAction), startAction)) .doesNotThrowAnyException(); } @@ -164,7 +163,7 @@ void createMemberActionTest6() { List.of(new MemberActionSaveAppRequest("쿠키", "IN"))); Action startAction = new Action(event, 2L); - assertThatCode(() -> memberActionFactory.createMemberActions(request, Arrays.asList(memberAction), startAction)) + assertThatCode(() -> memberActionFactory.createMemberActions(request, List.of(memberAction), startAction)) .isInstanceOf(IllegalArgumentException.class); } } From ade90fc820b770754006db542b601baa29c925d5 Mon Sep 17 00:00:00 2001 From: 3juhwan <13selfesteem91@naver.com> Date: Sun, 21 Jul 2024 14:25:10 +0900 Subject: [PATCH 10/14] =?UTF-8?q?refactor:=20memberActions=EB=A5=BC=20?= =?UTF-8?q?=EB=B3=B5=EC=82=AC=ED=95=B4=EC=84=9C=20=EB=82=B4=EB=A6=BC?= =?UTF-8?q?=EC=B0=A8=EC=88=9C=20=EC=A0=95=EB=A0=AC=ED=95=98=EB=8F=84?= =?UTF-8?q?=EB=A1=9D=20=EC=88=98=EC=A0=95,=20=EA=B2=80=EC=A6=9D=20?= =?UTF-8?q?=EB=A1=9C=EC=A7=81=20=EB=82=B4=EB=B6=80=EB=A1=9C=20=EC=9D=B4?= =?UTF-8?q?=EB=8F=99?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: kunsanglee Co-authored-by: Arachne --- .../application/MemberActionFactory.java | 19 ++++++++++--------- .../application/MemberActionFactoryTest.java | 8 +++----- 2 files changed, 13 insertions(+), 14 deletions(-) diff --git a/server/src/main/java/server/haengdong/application/MemberActionFactory.java b/server/src/main/java/server/haengdong/application/MemberActionFactory.java index a0969a367..9835b5de5 100644 --- a/server/src/main/java/server/haengdong/application/MemberActionFactory.java +++ b/server/src/main/java/server/haengdong/application/MemberActionFactory.java @@ -23,7 +23,6 @@ public List createMemberActions( List memberActions, Action action ) { - memberActions.sort(Comparator.comparing(MemberAction::getSequence)); validateActions(request, memberActions); Long memberGroupId = memberGroupIdProvider.createGroupId(); @@ -39,8 +38,12 @@ public List createMemberActions( } private void validateActions(MemberActionsSaveAppRequest request, List memberActions) { + List reverseSortedMemberActions = memberActions.stream() + .sorted(Comparator.comparing(MemberAction::getSequence).reversed()) + .toList(); + for (MemberActionSaveAppRequest action : request.actions()) { - validateAction(action, memberActions); + validateAction(action, reverseSortedMemberActions); } } @@ -52,12 +55,10 @@ private void validateAction(MemberActionSaveAppRequest request, List actions, String name, MemberActionStatus status) { - for (int i = actions.size() - 1; i >= 0; i--) { - MemberAction action = actions.get(i); - if (action.isSameName(name)) { - return action.isSameStatus(status); - } - } - return MemberActionStatus.IN != status; + return actions.stream() + .filter(action -> action.isSameName(name)) + .findFirst() + .map(action -> action.isSameStatus(status)) + .orElse(MemberActionStatus.IN != status); } } diff --git a/server/src/test/java/server/haengdong/application/MemberActionFactoryTest.java b/server/src/test/java/server/haengdong/application/MemberActionFactoryTest.java index b5d5d116e..c71a14107 100644 --- a/server/src/test/java/server/haengdong/application/MemberActionFactoryTest.java +++ b/server/src/test/java/server/haengdong/application/MemberActionFactoryTest.java @@ -5,8 +5,6 @@ import static org.assertj.core.api.Assertions.assertThatThrownBy; import static org.assertj.core.api.Assertions.tuple; -import java.util.ArrayList; -import java.util.Arrays; import java.util.List; import org.junit.jupiter.api.AfterEach; import org.junit.jupiter.api.DisplayName; @@ -57,7 +55,7 @@ void createMemberActionsTest() { MemberActionsSaveAppRequest request = new MemberActionsSaveAppRequest( List.of(new MemberActionSaveAppRequest("토다리", "OUT"))); - List unorderedMemberActions = Arrays.asList(memberAction2, memberAction1); + List unorderedMemberActions = List.of(memberAction2, memberAction1); Action startAction = new Action(event, 3L); assertThatThrownBy(() -> memberActionFactory.createMemberActions(request, unorderedMemberActions, startAction)) @@ -117,7 +115,7 @@ void createMemberActionsTest3() { Action startAction = new Action(event, 3L); assertThatCode( - () -> memberActionFactory.createMemberActions(request, Arrays.asList(memberAction1, memberAction2), + () -> memberActionFactory.createMemberActions(request, List.of(memberAction1, memberAction2), startAction)) .doesNotThrowAnyException(); } @@ -147,7 +145,7 @@ void createMemberActionTest5() { List.of(new MemberActionSaveAppRequest("쿠키", "OUT"))); Action startAction = new Action(event, 2L); - assertThatCode(() -> memberActionFactory.createMemberActions(request, new ArrayList<>(), startAction)) + assertThatCode(() -> memberActionFactory.createMemberActions(request, List.of(), startAction)) .isInstanceOf(IllegalArgumentException.class); } From 04a40e274c85cdd0efa62574340d042e9ba0641d Mon Sep 17 00:00:00 2001 From: 3juhwan <13selfesteem91@naver.com> Date: Sun, 21 Jul 2024 14:34:39 +0900 Subject: [PATCH 11/14] =?UTF-8?q?refactor:=20memberActions=EB=A5=BC=20?= =?UTF-8?q?=EB=B3=B5=EC=82=AC=ED=95=B4=EC=84=9C=20=EB=82=B4=EB=A6=BC?= =?UTF-8?q?=EC=B0=A8=EC=88=9C=20=EC=A0=95=EB=A0=AC=ED=95=98=EB=8F=84?= =?UTF-8?q?=EB=A1=9D=20=EC=88=98=EC=A0=95,=20=EA=B2=80=EC=A6=9D=20?= =?UTF-8?q?=EB=A1=9C=EC=A7=81=20=EB=82=B4=EB=B6=80=EB=A1=9C=20=EC=9D=B4?= =?UTF-8?q?=EB=8F=99?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../haengdong/application/MemberActionFactoryTest.java | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/server/src/test/java/server/haengdong/application/MemberActionFactoryTest.java b/server/src/test/java/server/haengdong/application/MemberActionFactoryTest.java index c71a14107..c4780575f 100644 --- a/server/src/test/java/server/haengdong/application/MemberActionFactoryTest.java +++ b/server/src/test/java/server/haengdong/application/MemberActionFactoryTest.java @@ -72,14 +72,15 @@ void createMemberActionsTest1() { MemberActionsSaveAppRequest memberActionsSaveAppRequest = new MemberActionsSaveAppRequest( List.of(new MemberActionSaveAppRequest("토다리", "OUT"))); + Action startAction = new Action(event, 2L); List memberActions = memberActionFactory.createMemberActions(memberActionsSaveAppRequest, - List.of(memberAction), action); + List.of(memberAction), startAction); assertThat(memberActions).hasSize(1) - .extracting("action", "memberName", "status") + .extracting(MemberAction::getAction, MemberAction::getMemberName, MemberAction::getStatus) .containsExactly( - tuple(action, "토다리", MemberActionStatus.OUT) + tuple(startAction, "토다리", MemberActionStatus.OUT) ); } From 60b2b34672d28b0d4e698d3b52036826b323e17f Mon Sep 17 00:00:00 2001 From: 3juhwan <13selfesteem91@naver.com> Date: Sun, 21 Jul 2024 15:05:54 +0900 Subject: [PATCH 12/14] =?UTF-8?q?refactor:=20=EC=BB=A8=EB=B2=A4=EC=85=98?= =?UTF-8?q?=EC=97=90=20=EB=A7=9E=EA=B2=8C=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../haengdong/application/MemberActionFactory.java | 14 +++++++++----- .../application/MemberActionFactoryTest.java | 2 +- 2 files changed, 10 insertions(+), 6 deletions(-) diff --git a/server/src/main/java/server/haengdong/application/MemberActionFactory.java b/server/src/main/java/server/haengdong/application/MemberActionFactory.java index 9835b5de5..3cc1dfc03 100644 --- a/server/src/main/java/server/haengdong/application/MemberActionFactory.java +++ b/server/src/main/java/server/haengdong/application/MemberActionFactory.java @@ -54,11 +54,15 @@ private void validateAction(MemberActionSaveAppRequest request, List actions, String name, MemberActionStatus status) { - return actions.stream() - .filter(action -> action.isSameName(name)) + private boolean isInvalidStatus( + List memberActions, + String memberName, + MemberActionStatus memberActionStatus + ) { + return memberActions.stream() + .filter(action -> action.isSameName(memberName)) .findFirst() - .map(action -> action.isSameStatus(status)) - .orElse(MemberActionStatus.IN != status); + .map(action -> action.isSameStatus(memberActionStatus)) + .orElse(MemberActionStatus.IN != memberActionStatus); } } diff --git a/server/src/test/java/server/haengdong/application/MemberActionFactoryTest.java b/server/src/test/java/server/haengdong/application/MemberActionFactoryTest.java index c4780575f..44e154c68 100644 --- a/server/src/test/java/server/haengdong/application/MemberActionFactoryTest.java +++ b/server/src/test/java/server/haengdong/application/MemberActionFactoryTest.java @@ -43,7 +43,7 @@ void tearDown() { eventRepository.deleteAllInBatch(); } - @DisplayName("액션 ID를 기준으로 정렬한 상태로 새로운 멤버 액션 요청을 검증한다.") + @DisplayName("이전 멤버 액션이 시퀀스 기준으로 정렬되지 않은 상태에서 새로운 멤버 액션 요청을 검증한다.") @Test void createMemberActionsTest() { Event event = eventRepository.save(new Event("우당탕탕 행동대장 백엔드 회식", "토다리_토큰")); From 1c1a2bdf25ea4f3088daa388720014e38e155fb4 Mon Sep 17 00:00:00 2001 From: 3juhwan <13selfesteem91@naver.com> Date: Sun, 21 Jul 2024 15:07:17 +0900 Subject: [PATCH 13/14] =?UTF-8?q?feat:=20=EC=82=AC=EC=9A=A9=EC=9E=90=20?= =?UTF-8?q?=EC=9D=B4=EB=A6=84=EC=9D=B4=20=EC=A4=91=EB=B3=B5=20=EC=9E=85?= =?UTF-8?q?=EB=A0=A5=EB=90=98=EB=8A=94=20=EC=98=88=EC=99=B8=20=EC=83=81?= =?UTF-8?q?=ED=99=A9=20=EA=B2=80=EC=A6=9D?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: kunsanglee Co-authored-by: Arachne --- .../application/MemberActionFactory.java | 12 +++++ .../application/MemberActionFactoryTest.java | 48 +++++++++++++++++++ 2 files changed, 60 insertions(+) diff --git a/server/src/main/java/server/haengdong/application/MemberActionFactory.java b/server/src/main/java/server/haengdong/application/MemberActionFactory.java index 3cc1dfc03..7dc97677e 100644 --- a/server/src/main/java/server/haengdong/application/MemberActionFactory.java +++ b/server/src/main/java/server/haengdong/application/MemberActionFactory.java @@ -23,6 +23,7 @@ public List createMemberActions( List memberActions, Action action ) { + validateMemberNames(request); validateActions(request, memberActions); Long memberGroupId = memberGroupIdProvider.createGroupId(); @@ -47,6 +48,17 @@ private void validateActions(MemberActionsSaveAppRequest request, List memberNames = request.actions().stream() + .map(MemberActionSaveAppRequest::name) + .toList(); + + long uniqueCount = memberNames.stream().distinct().count(); + if (uniqueCount != memberNames.size()) { + throw new IllegalArgumentException(); + } + } + private void validateAction(MemberActionSaveAppRequest request, List memberActions) { MemberActionStatus memberActionStatus = MemberActionStatus.of(request.status()); if (isInvalidStatus(memberActions, request.name(), memberActionStatus)) { diff --git a/server/src/test/java/server/haengdong/application/MemberActionFactoryTest.java b/server/src/test/java/server/haengdong/application/MemberActionFactoryTest.java index 44e154c68..a0ac9916f 100644 --- a/server/src/test/java/server/haengdong/application/MemberActionFactoryTest.java +++ b/server/src/test/java/server/haengdong/application/MemberActionFactoryTest.java @@ -165,4 +165,52 @@ void createMemberActionTest6() { assertThatCode(() -> memberActionFactory.createMemberActions(request, List.of(memberAction), startAction)) .isInstanceOf(IllegalArgumentException.class); } + + @DisplayName("한 명의 사용자는 동시에 여러 번 입장할 수 없다.") + @Test + void createMemberActionTest7() { + Event event = eventRepository.save(new Event("test", "TOKEN")); + + MemberActionsSaveAppRequest request = new MemberActionsSaveAppRequest( + List.of(new MemberActionSaveAppRequest("쿠키", "IN"), + new MemberActionSaveAppRequest("쿠키", "IN"))); + Action startAction = new Action(event, 1L); + + assertThatCode(() -> memberActionFactory.createMemberActions(request, List.of(), startAction)) + .isInstanceOf(IllegalArgumentException.class); + } + + @DisplayName("한 명의 사용자는 동시에 여러 번 퇴장할 수 없다.") + @Test + void createMemberActionTest8() { + Event event = eventRepository.save(new Event("test", "TOKEN")); + Action action = new Action(event, 1L); + MemberAction memberAction = new MemberAction(action, "쿠키", MemberActionStatus.IN, 1L); + memberActionRepository.save(memberAction); + + MemberActionsSaveAppRequest request = new MemberActionsSaveAppRequest( + List.of(new MemberActionSaveAppRequest("쿠키", "OUT"), + new MemberActionSaveAppRequest("쿠키", "OUT"))); + Action startAction = new Action(event, 2L); + + assertThatCode(() -> memberActionFactory.createMemberActions(request, List.of(memberAction), startAction)) + .isInstanceOf(IllegalArgumentException.class); + } + + @DisplayName("한 명의 사용자는 입장과 퇴장을 동시에 할 수 없다.") + @Test + void createMemberActionTest9() { + Event event = eventRepository.save(new Event("test", "TOKEN")); + Action action = new Action(event, 1L); + MemberAction memberAction = new MemberAction(action, "쿠키", MemberActionStatus.IN, 1L); + memberActionRepository.save(memberAction); + + MemberActionsSaveAppRequest request = new MemberActionsSaveAppRequest( + List.of(new MemberActionSaveAppRequest("쿠키", "IN"), + new MemberActionSaveAppRequest("쿠키", "OUT"))); + Action startAction = new Action(event, 2L); + + assertThatCode(() -> memberActionFactory.createMemberActions(request, List.of(memberAction), startAction)) + .isInstanceOf(IllegalArgumentException.class); + } } From c7de8bdb16f119ef17156481d6bf91ff6e0567f7 Mon Sep 17 00:00:00 2001 From: 3juhwan <13selfesteem91@naver.com> Date: Sun, 21 Jul 2024 15:19:28 +0900 Subject: [PATCH 14/14] =?UTF-8?q?refactor:=20=EB=A9=94=EC=84=9C=EB=93=9C?= =?UTF-8?q?=20=EC=88=9C=EC=84=9C=20=EB=B3=80=EB=8E=A1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Arachne --- .../application/MemberActionFactory.java | 20 +++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/server/src/main/java/server/haengdong/application/MemberActionFactory.java b/server/src/main/java/server/haengdong/application/MemberActionFactory.java index 7dc97677e..d583967a0 100644 --- a/server/src/main/java/server/haengdong/application/MemberActionFactory.java +++ b/server/src/main/java/server/haengdong/application/MemberActionFactory.java @@ -38,16 +38,6 @@ public List createMemberActions( return createdMemberActions; } - private void validateActions(MemberActionsSaveAppRequest request, List memberActions) { - List reverseSortedMemberActions = memberActions.stream() - .sorted(Comparator.comparing(MemberAction::getSequence).reversed()) - .toList(); - - for (MemberActionSaveAppRequest action : request.actions()) { - validateAction(action, reverseSortedMemberActions); - } - } - private void validateMemberNames(MemberActionsSaveAppRequest request) { List memberNames = request.actions().stream() .map(MemberActionSaveAppRequest::name) @@ -59,6 +49,16 @@ private void validateMemberNames(MemberActionsSaveAppRequest request) { } } + private void validateActions(MemberActionsSaveAppRequest request, List memberActions) { + List reverseSortedMemberActions = memberActions.stream() + .sorted(Comparator.comparing(MemberAction::getSequence).reversed()) + .toList(); + + for (MemberActionSaveAppRequest action : request.actions()) { + validateAction(action, reverseSortedMemberActions); + } + } + private void validateAction(MemberActionSaveAppRequest request, List memberActions) { MemberActionStatus memberActionStatus = MemberActionStatus.of(request.status()); if (isInvalidStatus(memberActions, request.name(), memberActionStatus)) {