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] 인원 변동 기능 구현 #47

Merged
merged 15 commits into from
Jul 21, 2024
Merged
Show file tree
Hide file tree
Changes from 4 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 @@ -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);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
package server.haengdong.application;

import java.util.List;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import server.haengdong.application.request.MemberActionSaveListAppRequest;
import server.haengdong.domain.Event;
import server.haengdong.domain.MemberAction;
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 MemberActionFactory memberActionFactory;
3Juhwan marked this conversation as resolved.
Show resolved Hide resolved

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

List<MemberAction> findMemberActions = memberActionRepository.findAllByEvent(event);
List<MemberAction> memberActions = memberActionFactory.createMemberActions(request, findMemberActions, event);
memberActionRepository.saveAll(memberActions);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +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(Action action, Long memberGroupId) {
return new MemberAction(action, name, MemberActionStatus.of(status), memberGroupId);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
package server.haengdong.application.request;

import java.util.List;

public record MemberActionSaveListAppRequest(List<MemberActionSaveAppRequest> actions) {
3Juhwan marked this conversation as resolved.
Show resolved Hide resolved
}
5 changes: 5 additions & 0 deletions server/src/main/java/server/haengdong/domain/Action.java
Original file line number Diff line number Diff line change
Expand Up @@ -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;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ public class EventStep {

@ManyToOne(fetch = FetchType.LAZY)
private Event event;

private String name;

private Long sequence;
Expand Down
18 changes: 17 additions & 1 deletion server/src/main/java/server/haengdong/domain/MemberAction.java
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
package server.haengdong.domain;

import jakarta.persistence.CascadeType;
import jakarta.persistence.Entity;
import jakarta.persistence.EnumType;
import jakarta.persistence.Enumerated;
Expand All @@ -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;
Expand All @@ -30,4 +31,19 @@ public class MemberAction {
private MemberActionStatus status;

private Long memberGroupId;

public MemberAction(Action action, String memberName, MemberActionStatus status, Long memberGroupId) {
this.action = action;
this.memberName = memberName;
this.status = status;
this.memberGroupId = memberGroupId;
}

public boolean isSameName(String name) {
return memberName.equals(name);
}

public boolean isAvailable(MemberActionStatus memberActionStatus) {
return status.isOpposite(memberActionStatus);
}
}
Original file line number Diff line number Diff line change
@@ -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;
kunsanglee marked this conversation as resolved.
Show resolved Hide resolved

@RequiredArgsConstructor
@Component
public class MemberActionFactory {

private final ActionRepository actionRepository;
private final MemberGroupIdProvider memberGroupIdProvider;

public List<MemberAction> createMemberActions(
MemberActionSaveListAppRequest request,
List<MemberAction> memberActions,
Event event
) {
validateActions(request, memberActions);
Long memberGroupId = memberGroupIdProvider.createGroupId();
long lastSequence = getLastSequence(event);
List<MemberAction> memberActionList = new ArrayList<>();
List<MemberActionSaveAppRequest> actions = request.actions();
for (MemberActionSaveAppRequest appRequest : actions) {
Action action = new Action(event, ++lastSequence);
MemberAction memberAction = appRequest.toMemberAction(action, memberGroupId);
memberActionList.add(memberAction);
}
return memberActionList;
3Juhwan marked this conversation as resolved.
Show resolved Hide resolved
}

private void validateActions(MemberActionSaveListAppRequest request, List<MemberAction> memberActions) {
for (MemberActionSaveAppRequest action : request.actions()) {
validateAction(memberActions, action);
}
}

private void validateAction(List<MemberAction> memberActions, MemberActionSaveAppRequest action) {
if (!isAvailableAction(memberActions, action.name(), action.status())) {
3Juhwan marked this conversation as resolved.
Show resolved Hide resolved
throw new IllegalArgumentException();
}
}

private long getLastSequence(Event event) {
return actionRepository.findLastByEvent(event)
.map(Action::getSequence)
.orElse(0L);
}

private boolean isAvailableAction(List<MemberAction> 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);
khabh marked this conversation as resolved.
Show resolved Hide resolved
}
}
Original file line number Diff line number Diff line change
@@ -1,7 +1,24 @@
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));
}

public static boolean isMemberStatusIn(MemberActionStatus memberActionStatus) {
return IN == memberActionStatus;
}
3Juhwan marked this conversation as resolved.
Show resolved Hide resolved

public boolean isOpposite(MemberActionStatus memberActionStatus) {
return this != memberActionStatus;
}
3Juhwan marked this conversation as resolved.
Show resolved Hide resolved
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
package server.haengdong.domain;

import org.springframework.stereotype.Component;

@Component
public class MemberGroupIdProvider {

public Long createGroupId() {
return System.currentTimeMillis();
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +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<Action, Long> {

@Query("""
SELECT a
FROM Action a
WHERE a.event = :event
ORDER BY a.sequence DESC
LIMIT 1
""")
Optional<Action> findLastByEvent(@Param("event") Event event);
3Juhwan marked this conversation as resolved.
Show resolved Hide resolved
}
Original file line number Diff line number Diff line change
@@ -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<Event, Long> {
Optional<Event> findByToken(String token);
}
Original file line number Diff line number Diff line change
@@ -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<MemberAction, Long> {

@Query("select m from MemberAction m where m.action.event = :event")
3Juhwan marked this conversation as resolved.
Show resolved Hide resolved
List<MemberAction> findAllByEvent(@Param("event") Event event);
3Juhwan marked this conversation as resolved.
Show resolved Hide resolved
}
Original file line number Diff line number Diff line change
@@ -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<Void> saveMemberAction(
@PathVariable("token") String token,
@RequestBody MemberActionSaveListRequest request
) {
memberActionService.saveMemberAction(token, request.toAppRequest());

return ResponseEntity.ok().build();
}
}
Original file line number Diff line number Diff line change
@@ -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<MemberActionSaveRequest> actions) {

public MemberActionSaveListAppRequest toAppRequest() {
List<MemberActionSaveAppRequest> appRequests = actions.stream()
.map(MemberActionSaveRequest::toAppRequest)
.toList();

return new MemberActionSaveListAppRequest(appRequests);
}
}
Original file line number Diff line number Diff line change
@@ -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);
}
}
Loading