Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[BE] 현재 참여 인원 조회 #70

Merged
merged 1 commit into from
Jul 24, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -5,12 +5,14 @@
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import server.haengdong.application.request.MemberActionsSaveAppRequest;
import server.haengdong.application.response.CurrentMemberAppResponse;
import server.haengdong.domain.action.Action;
import server.haengdong.domain.event.Event;
import server.haengdong.domain.action.MemberAction;
import server.haengdong.domain.action.ActionRepository;
import server.haengdong.domain.event.EventRepository;
import server.haengdong.domain.action.CurrentMembers;
import server.haengdong.domain.action.MemberAction;
import server.haengdong.domain.action.MemberActionRepository;
import server.haengdong.domain.event.Event;
import server.haengdong.domain.event.EventRepository;

@RequiredArgsConstructor
@Transactional(readOnly = true)
Expand All @@ -24,8 +26,7 @@ public class MemberActionService {

@Transactional
public void saveMemberAction(String token, MemberActionsSaveAppRequest request) {
Event event = eventRepository.findByToken(token)
.orElseThrow(() -> new IllegalArgumentException("event not found"));
Event event = findEvent(token);

List<MemberAction> findMemberActions = memberActionRepository.findAllByEvent(event);
Action action = createStartAction(event);
Expand All @@ -38,4 +39,20 @@ private Action createStartAction(Event event) {
.map(Action::next)
.orElse(Action.createFirst(event));
}

public List<CurrentMemberAppResponse> getCurrentMembers(String token) {
Event event = findEvent(token);
List<MemberAction> findMemberActions = memberActionRepository.findAllByEvent(event);
CurrentMembers currentMembers = CurrentMembers.of(findMemberActions);

return currentMembers.getMembers()
.stream()
.map(CurrentMemberAppResponse::new)
.toList();
}

private Event findEvent(String token) {
return eventRepository.findByToken(token)
.orElseThrow(() -> new IllegalArgumentException("event not found"));
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
package server.haengdong.application.response;

import server.haengdong.domain.action.MemberAction;

public record CurrentMemberAppResponse(String name) {

public static CurrentMemberAppResponse of(MemberAction memberAction) {
return new CurrentMemberAppResponse(memberAction.getMemberName());
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
package server.haengdong.domain.action;

import java.util.Comparator;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import lombok.AccessLevel;
import lombok.Getter;
import lombok.RequiredArgsConstructor;

@Getter
@RequiredArgsConstructor(access = AccessLevel.PRIVATE)
public class CurrentMembers {

private final Set<String> members;

public static CurrentMembers of(List<MemberAction> memberActions) {
List<MemberAction> sortedMemberActions = getSortedMemberActions(memberActions);
Set<String> members = new HashSet<>();
for (MemberAction memberAction : sortedMemberActions) {
String member = memberAction.getMemberName();
if (memberAction.isSameStatus(MemberActionStatus.IN)) {
members.add(member);
continue;
}
members.remove(member);
}

return new CurrentMembers(members);
}

private static List<MemberAction> getSortedMemberActions(List<MemberAction> memberActions) {
return memberActions.stream()
.sorted(Comparator.comparing(MemberAction::getSequence))
.toList();
}
}
Original file line number Diff line number Diff line change
@@ -1,13 +1,17 @@
package server.haengdong.presentation;

import java.util.List;
import lombok.RequiredArgsConstructor;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RestController;
import server.haengdong.application.MemberActionService;
import server.haengdong.application.response.CurrentMemberAppResponse;
import server.haengdong.presentation.request.MemberActionsSaveRequest;
import server.haengdong.presentation.response.CurrentMembersResponse;

@RequiredArgsConstructor
@RestController
Expand All @@ -24,4 +28,12 @@ public ResponseEntity<Void> saveMemberAction(

return ResponseEntity.ok().build();
}

@GetMapping("/api/events/{token}/members/current")
public ResponseEntity<CurrentMembersResponse> getCurrentMembers(@PathVariable("token") String token) {
List<CurrentMemberAppResponse> currentMembers = memberActionService.getCurrentMembers(token);

return ResponseEntity.ok()
.body(CurrentMembersResponse.of(currentMembers));
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
package server.haengdong.presentation.response;

import server.haengdong.application.response.CurrentMemberAppResponse;

public record CurrentMemberResponse(String name) {

public static CurrentMemberResponse of(CurrentMemberAppResponse response) {
return new CurrentMemberResponse(response.name());
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
package server.haengdong.presentation.response;

import java.util.List;
import server.haengdong.application.response.CurrentMemberAppResponse;

public record CurrentMembersResponse(List<CurrentMemberResponse> members) {

public static CurrentMembersResponse of(List<CurrentMemberAppResponse> currentMembers) {
List<CurrentMemberResponse> responses = currentMembers.stream()
.map(CurrentMemberResponse::of)
.toList();

return new CurrentMembersResponse(responses);
}
}
Original file line number Diff line number Diff line change
@@ -1,6 +1,9 @@
package server.haengdong.application;

import static org.assertj.core.api.Assertions.assertThatCode;
import static org.assertj.core.api.Assertions.assertThatThrownBy;
import static server.haengdong.domain.action.MemberActionStatus.IN;
import static server.haengdong.domain.action.MemberActionStatus.OUT;

import java.util.List;
import org.junit.jupiter.api.AfterEach;
Expand All @@ -11,12 +14,11 @@
import server.haengdong.application.request.MemberActionSaveAppRequest;
import server.haengdong.application.request.MemberActionsSaveAppRequest;
import server.haengdong.domain.action.Action;
import server.haengdong.domain.event.Event;
import server.haengdong.domain.action.MemberAction;
import server.haengdong.domain.action.MemberActionStatus;
import server.haengdong.domain.action.ActionRepository;
import server.haengdong.domain.event.EventRepository;
import server.haengdong.domain.action.MemberAction;
import server.haengdong.domain.action.MemberActionRepository;
import server.haengdong.domain.event.Event;
import server.haengdong.domain.event.EventRepository;

@SpringBootTest
class MemberActionServiceTest {
Expand All @@ -40,37 +42,37 @@ void tearDown() {
eventRepository.deleteAllInBatch();
}

@DisplayName("현재 행사에 참여하고 있는 경우에 나갈 수 있다")
@DisplayName("현재 행사에 참여하고 있는 경우에 나갈 수 있다.")
@Test
void saveMemberActionTest() {
Event event = eventRepository.save(new Event("test", "TOKEN"));
Action action = new Action(event, 1L);
MemberAction memberAction = new MemberAction(action, "망쵸", MemberActionStatus.IN, 1L);
MemberAction memberAction = new MemberAction(action, "망쵸", IN, 1L);
memberActionRepository.save(memberAction);

assertThatCode(() -> memberActionService.saveMemberAction("TOKEN", new MemberActionsSaveAppRequest(
List.of(new MemberActionSaveAppRequest("망쵸", "OUT")))))
.doesNotThrowAnyException();
}

@DisplayName("행사에서 퇴장한 경우에 입장할 수 있다")
@DisplayName("행사에서 퇴장한 경우에 입장할 수 있다.")
@Test
void saveMemberActionTest1() {
Event event = eventRepository.save(new Event("test", "TOKEN"));
Action actionOne = new Action(event, 1L);
MemberAction memberActionOne = new MemberAction(actionOne, "망쵸", MemberActionStatus.IN, 1L);
MemberAction memberActionOne = new MemberAction(actionOne, "망쵸", IN, 1L);
Comment on lines -61 to +63
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

static import 할 필요가 있을까요?

memberActionRepository.save(memberActionOne);

Action actionTwo = new Action(event, 2L);
MemberAction memberActionTwo = new MemberAction(actionTwo, "망쵸", MemberActionStatus.OUT, 1L);
MemberAction memberActionTwo = new MemberAction(actionTwo, "망쵸", OUT, 1L);
memberActionRepository.save(memberActionTwo);

assertThatCode(() -> memberActionService.saveMemberAction("TOKEN", new MemberActionsSaveAppRequest(
List.of(new MemberActionSaveAppRequest("망쵸", "IN")))))
.doesNotThrowAnyException();
}

@DisplayName("행사에 입장하지 않았을 경우 퇴장할 수 없다")
@DisplayName("행사에 입장하지 않았을 경우 퇴장할 수 없다.")
@Test
void saveMemberActionTest2() {
MemberActionsSaveAppRequest appRequest = new MemberActionsSaveAppRequest(
Expand All @@ -79,4 +81,11 @@ void saveMemberActionTest2() {
assertThatCode(() -> memberActionService.saveMemberAction("TOKEN", appRequest))
.isInstanceOf(IllegalArgumentException.class);
}

@DisplayName("이벤트가 없으면 현재 참여 인원을 조회할 수 없다.")
@Test
void getCurrentMembers() {
assertThatThrownBy(() -> memberActionService.getCurrentMembers("token"))
.isInstanceOf(IllegalArgumentException.class);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
package server.haengdong.domain.action;

import static org.assertj.core.api.Assertions.assertThat;
import static server.haengdong.domain.action.MemberActionStatus.IN;
import static server.haengdong.domain.action.MemberActionStatus.OUT;
Comment on lines +4 to +5
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

이곳도 static import 해야 할까요?


import java.util.List;
import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Test;
import server.haengdong.domain.event.Event;

class CurrentMembersTest {

@DisplayName("인원 변동 이력으로 현재 참여 인원을 계산한다.")
@Test
void of() {
Event event = new Event("test", "TOKEN");
List<MemberAction> memberActions = List.of(
new MemberAction(new Action(event, 1L), "망쵸", IN, 1L),
new MemberAction(new Action(event, 2L), "백호", IN, 1L),
new MemberAction(new Action(event, 3L), "백호", OUT, 1L),
new MemberAction(new Action(event, 4L), "웨디", IN, 1L)
);

CurrentMembers currentMembers = CurrentMembers.of(memberActions);

assertThat(currentMembers.getMembers())
.containsExactlyInAnyOrder("망쵸", "웨디");
}
}
Original file line number Diff line number Diff line change
@@ -1,5 +1,9 @@
package server.haengdong.presentation;

import static org.hamcrest.Matchers.equalTo;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.BDDMockito.given;
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get;
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post;
import static org.springframework.test.web.servlet.result.MockMvcResultHandlers.print;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
Expand All @@ -13,7 +17,9 @@
import org.springframework.boot.test.mock.mockito.MockBean;
import org.springframework.http.MediaType;
import org.springframework.test.web.servlet.MockMvc;
import org.springframework.test.web.servlet.result.MockMvcResultMatchers;
import server.haengdong.application.MemberActionService;
import server.haengdong.application.response.CurrentMemberAppResponse;
import server.haengdong.presentation.request.MemberActionSaveRequest;
import server.haengdong.presentation.request.MemberActionsSaveRequest;

Expand Down Expand Up @@ -46,4 +52,19 @@ void saveMemberActionTest() throws Exception {
.andDo(print())
.andExpect(status().isOk());
}

@DisplayName("현재 참여 인원을 조회합니다.")
@Test
void getCurrentMembers() throws Exception {
List<CurrentMemberAppResponse> currentMemberAppResponses = List.of(new CurrentMemberAppResponse("소하"), new CurrentMemberAppResponse("토다리"));

given(memberActionService.getCurrentMembers(any())).willReturn(currentMemberAppResponses);

mockMvc.perform(get("/api/events/{token}/members/current", "token")
.accept(MediaType.APPLICATION_JSON))
.andDo(print())
.andExpect(status().isOk())
.andExpect(MockMvcResultMatchers.jsonPath("$.members[0].name").value(equalTo("소하")))
.andExpect(MockMvcResultMatchers.jsonPath("$.members[1].name").value(equalTo("토다리")));
}
}
Loading