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 5 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,63 @@
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.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 MemberGroupIdProvider memberGroupIdProvider;

public List<MemberAction> createMemberActions(
MemberActionsSaveAppRequest request,
List<MemberAction> memberActions,
Action action
) {
3Juhwan marked this conversation as resolved.
Show resolved Hide resolved
memberActions.sort(Comparator.comparing(MemberAction::getSequence));
Arachneee marked this conversation as resolved.
Show resolved Hide resolved
validateActions(request, memberActions);

Long memberGroupId = memberGroupIdProvider.createGroupId();
List<MemberAction> createdMemberActions = new ArrayList<>();
List<MemberActionSaveAppRequest> actions = request.actions();
for (MemberActionSaveAppRequest appRequest : actions) {
MemberAction memberAction = appRequest.toMemberAction(action, memberGroupId);
createdMemberActions.add(memberAction);
action = action.next();
}

return createdMemberActions;
}

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

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

private boolean isInvalidStatus(List<MemberAction> 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);
kunsanglee marked this conversation as resolved.
Show resolved Hide resolved
3Juhwan marked this conversation as resolved.
Show resolved Hide resolved
}
}
return MemberActionStatus.IN != status;
3Juhwan marked this conversation as resolved.
Show resolved Hide resolved
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
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.MemberActionsSaveAppRequest;
import server.haengdong.domain.Action;
import server.haengdong.domain.Event;
import server.haengdong.domain.MemberAction;
import server.haengdong.persistence.ActionRepository;
import server.haengdong.persistence.EventRepository;
import server.haengdong.persistence.MemberActionRepository;

@RequiredArgsConstructor
@Transactional(readOnly = true)
@Service
public class MemberActionService {

private final MemberActionFactory memberActionFactory;
private final MemberActionRepository memberActionRepository;
private final EventRepository eventRepository;
private final ActionRepository actionRepository;

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

List<MemberAction> findMemberActions = memberActionRepository.findAllByEvent(event);
Action action = createStartAction(event);
List<MemberAction> 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));
}
}
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
}
15 changes: 15 additions & 0 deletions server/src/main/java/server/haengdong/domain/Action.java
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,8 @@
@Entity
public class Action {

private static final long FIRST_SEQUENCE = 1L;

@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
Expand All @@ -23,4 +25,17 @@ public class Action {
private Event event;

private Long sequence;

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);
3Juhwan marked this conversation as resolved.
Show resolved Hide resolved
}
}
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
22 changes: 21 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,23 @@ 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 isSameStatus(MemberActionStatus memberActionStatus) {
return status == memberActionStatus;
}

public Long getSequence() {
return action.getSequence();
}
}
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