Skip to content
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 @@ -81,14 +81,26 @@ public Page<Task> findAllTasks(Pageable pageable, FilterTaskListRequest filterTa
}

@Override
public Optional<Task> findPrevOrderTaskByProcessorIdAndStatus(Long processorId, TaskStatus taskStatus, Long processorOrder) {
Optional<TaskEntity> taskEntity = taskRepository.findTopByProcessor_MemberIdAndTaskStatusAndProcessorOrderLessThanOrderByProcessorOrderDesc(processorId, taskStatus, processorOrder);
public Optional<Task> findPrevOrderTaskByProcessorOrderAndStatus(Long processorId, TaskStatus taskStatus, Long processorOrder) {
Optional<TaskEntity> taskEntity = taskRepository.findTopByProcessor_MemberIdAndTaskStatusAndProcessorOrderLessThanOrderByProcessorOrderAsc(processorId, taskStatus, processorOrder);
return taskEntity.map(taskPersistenceMapper::toDomain);
}

@Override
public Optional<Task> findNextOrderTaskByProcessorIdAndStatus(Long processorId, TaskStatus taskStatus, Long processorOrder) {
Optional<TaskEntity> taskEntity = taskRepository.findTopByProcessor_MemberIdAndTaskStatusAndProcessorOrderAfterOrderByProcessorOrderDesc(processorId, taskStatus, processorOrder);
public Optional<Task> findNextOrderTaskByProcessorOrderAndStatus(Long processorId, TaskStatus taskStatus, Long processorOrder) {
Optional<TaskEntity> taskEntity = taskRepository.findTopByProcessor_MemberIdAndTaskStatusAndProcessorOrderAfterOrderByProcessorOrderAsc(processorId, taskStatus, processorOrder);
return taskEntity.map(taskPersistenceMapper::toDomain);
}

@Override
public Optional<Task> findPrevOrderTaskByTaskIdAndStatus(Long processorId, TaskStatus taskStatus, Long taskId) {
Optional<TaskEntity> taskEntity = taskRepository.findTopByProcessor_MemberIdAndTaskStatusAndTaskIdLessThanOrderByTaskIdDesc(processorId, taskStatus, taskId);
return taskEntity.map(taskPersistenceMapper::toDomain);
}

@Override
public Optional<Task> findNextOrderTaskByTaskIdAndStatus(Long processorId, TaskStatus taskStatus, Long taskId) {
Optional<TaskEntity> taskEntity = taskRepository.findTopByProcessor_MemberIdAndTaskStatusAndTaskIdGreaterThanOrderByTaskIdAsc(processorId, taskStatus, taskId);
return taskEntity.map(taskPersistenceMapper::toDomain);
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,6 @@ public interface TaskRepository extends JpaRepository<TaskEntity, Long>, TaskCus

@Query("select t from TaskEntity t join fetch t.processor p" +
" where t.updatedAt between :updatedAtAfter and :updatedAtBefore")

List<TaskEntity> findYesterdayTaskByUpdatedAtIsBetween(
@Param("updatedAtAfter") LocalDateTime updatedAtAfter,
@Param("updatedAtBefore") LocalDateTime updatedAtBefore
Expand All @@ -49,14 +48,17 @@ List<TaskEntity> findTasksWithTaskStatusAndCompletedAt(

Optional<TaskEntity> findByTaskIdAndTaskStatus(Long id, TaskStatus status);

Optional<TaskEntity> findTopByProcessor_MemberIdAndTaskStatusAndProcessorOrderLessThanOrderByProcessorOrderDesc(Long processorId, TaskStatus taskStatus, Long processorOrder);
Optional<TaskEntity> findTopByProcessor_MemberIdAndTaskStatusAndProcessorOrderLessThanOrderByProcessorOrderAsc(Long processorId, TaskStatus taskStatus, Long processorOrder);

Optional<TaskEntity> findTopByProcessor_MemberIdAndTaskStatusAndProcessorOrderAfterOrderByProcessorOrderDesc(
Optional<TaskEntity> findTopByProcessor_MemberIdAndTaskStatusAndProcessorOrderAfterOrderByProcessorOrderAsc(
Long processorId, TaskStatus taskStatus, Long processorOrder);

@Query("SELECT t FROM TaskEntity t JOIN FETCH t.processor p WHERE (:memberId IS NULL OR p.memberId = :memberId) ")
Page<TeamTaskResponse> findTeamStatus(@Param("memberId") Long memberId, FilterTeamStatusRequest filter, Pageable pageable);

Optional<TaskEntity> findTopByProcessor_MemberIdAndTaskStatusAndTaskIdLessThanOrderByTaskIdDesc(Long processorId, TaskStatus taskStatus, Long taskId);

Optional<TaskEntity> findTopByProcessor_MemberIdAndTaskStatusAndTaskIdGreaterThanOrderByTaskIdAsc(Long processorId, TaskStatus status, Long taskId);


}
Original file line number Diff line number Diff line change
Expand Up @@ -28,9 +28,13 @@ public interface LoadTaskPort {

Optional<Task> findByIdAndStatus(Long id, TaskStatus status);

Optional<Task> findPrevOrderTaskByProcessorIdAndStatus(Long processorId, TaskStatus taskStatus, Long processorOrder);
Optional<Task> findPrevOrderTaskByProcessorOrderAndStatus(Long processorId, TaskStatus taskStatus, Long processorOrder);

Optional<Task> findNextOrderTaskByProcessorIdAndStatus(Long processorId, TaskStatus taskStatus, Long processorOrder);
Optional<Task> findNextOrderTaskByProcessorOrderAndStatus(Long processorId, TaskStatus taskStatus, Long processorOrder);

Optional<Task> findPrevOrderTaskByTaskIdAndStatus(Long processorId, TaskStatus taskStatus, Long taskId);

Optional<Task> findNextOrderTaskByTaskIdAndStatus(Long processorId, TaskStatus taskStatus, Long taskId);

List<Task> findTaskBoardByFilter(Long processorId, List<TaskStatus> statuses, LocalDateTime untilDateTime, FilterTaskBoardRequest request);

Expand Down
Original file line number Diff line number Diff line change
@@ -1,12 +1,14 @@
package clap.server.application.service.task;

import clap.server.adapter.inbound.web.dto.task.request.UpdateTaskOrderRequest;
import clap.server.adapter.outbound.persistense.entity.notification.constant.NotificationType;
import clap.server.adapter.outbound.persistense.entity.task.constant.TaskStatus;
import clap.server.application.port.inbound.domain.MemberService;
import clap.server.application.port.inbound.domain.TaskService;
import clap.server.application.port.inbound.task.UpdateTaskBoardUsecase;
import clap.server.application.port.inbound.task.UpdateTaskOrderAndStatusUsecase;
import clap.server.application.port.outbound.task.LoadTaskPort;
import clap.server.application.service.webhook.SendNotificationService;
import clap.server.common.annotation.architecture.ApplicationService;
import clap.server.domain.model.member.Member;
import clap.server.domain.model.task.Task;
Expand All @@ -19,13 +21,16 @@
import lombok.extern.slf4j.Slf4j;
import org.springframework.transaction.annotation.Transactional;

import java.util.List;

@Slf4j
@ApplicationService
@RequiredArgsConstructor
class UpdateTaskBoardService implements UpdateTaskBoardUsecase, UpdateTaskOrderAndStatusUsecase {
private final MemberService memberService;
private final TaskService taskService;
private final LoadTaskPort loadTaskPort;
private final SendNotificationService sendNotificationService;

private final TaskOrderCalculationPolicy taskOrderCalculationPolicy;
private final ProcessorValidationPolicy processorValidationPolicy;
Expand Down Expand Up @@ -53,15 +58,15 @@ public void updateTaskOrder(Long processorId, UpdateTaskOrderRequest request) {
if (request.prevTaskId() == 0) {
Task nextTask = findByIdAndStatus(request.nextTaskId(), targetTask.getTaskStatus());
// 해당 상태에서 바로 앞에 있는 작업 찾기
Task prevTask = loadTaskPort.findPrevOrderTaskByProcessorIdAndStatus(processorId, targetTask.getTaskStatus(), nextTask.getProcessorOrder()).orElse(null);
Task prevTask = loadTaskPort.findPrevOrderTaskByProcessorOrderAndStatus(processorId, targetTask.getTaskStatus(), nextTask.getProcessorOrder()).orElse(null);
long newOrder = taskOrderCalculationPolicy.calculateOrderForTop(prevTask, nextTask);
updateNewTaskOrder(targetTask, newOrder);
}
// 가장 하위로 이동
else if (request.nextTaskId() == 0) {
Task prevTask = findByIdAndStatus(request.prevTaskId(), targetTask.getTaskStatus());
// 해당 상태에서 바로 뒤에 있는 작업 찾기
Task nextTask = loadTaskPort.findNextOrderTaskByProcessorIdAndStatus(processorId, targetTask.getTaskStatus(), prevTask.getProcessorOrder()).orElse(null);
Task nextTask = loadTaskPort.findNextOrderTaskByProcessorOrderAndStatus(processorId, targetTask.getTaskStatus(), prevTask.getProcessorOrder()).orElse(null);
long newOrder = taskOrderCalculationPolicy.calculateOrderForBottom(prevTask, nextTask);
updateNewTaskOrder(targetTask, newOrder);
} else {
Expand Down Expand Up @@ -98,49 +103,87 @@ public void updateTaskOrderAndStatus(Long processorId, UpdateTaskOrderRequest re
Task targetTask = taskService.findById(request.targetTaskId());
processorValidationPolicy.validateProcessor(processorId, targetTask);

if (request.prevTaskId() == 0) {
Task nextTask = findByIdAndStatus(request.nextTaskId(), targetStatus);
Task updatedTask;
Task prevTask;
Task nextTask;

// 조회된 작업 보드에서 하나의 작업만 존재하고, 이 작업을 이동할 때
if (request.prevTaskId() == 0 && request.nextTaskId() == 0) {

// 요청 시간 기준으로 가장 가장 근접한 이전의 Task를 조회
prevTask = loadTaskPort.findPrevOrderTaskByTaskIdAndStatus(processorId, targetStatus, targetTask.getTaskId()).orElse(null);
if (prevTask != null) {
// 이전 Task가 있다면 바로 다음의 Task 조회
nextTask = loadTaskPort.findNextOrderTaskByProcessorOrderAndStatus(processorId, targetStatus, prevTask.getProcessorOrder()).orElse(null);
} // 요청 시간 기준으로 가장 가장 근접한 이후의 Task를 조회
else
nextTask = loadTaskPort.findNextOrderTaskByTaskIdAndStatus(processorId, targetStatus, targetTask.getTaskId()).orElse(null);

// 하나의 task만 존재할 경우 상태만 update
if (prevTask == null && nextTask == null) {
targetTask.updateTaskStatus(targetStatus);
updatedTask = taskService.upsert(targetTask);
} else if (prevTask == null) {
long newOrder = taskOrderCalculationPolicy.calculateOrderForBottom(null, nextTask);
updatedTask = updateNewTaskOrderAndStatus(targetStatus, targetTask, newOrder);
} else if (nextTask == null) {
long newOrder = taskOrderCalculationPolicy.calculateOrderForBottom(prevTask, null);
updatedTask = updateNewTaskOrderAndStatus(targetStatus, targetTask, newOrder);
} else {
long newOrder = taskOrderCalculationPolicy.calculateNewProcessorOrder(prevTask.getProcessorOrder(), nextTask.getProcessorOrder());
updatedTask = updateNewTaskOrderAndStatus(targetStatus, targetTask, newOrder);
}
} else if (request.prevTaskId() == 0) {
nextTask = findByIdAndStatus(request.nextTaskId(), targetStatus);
// 해당 상태에서 바로 앞 있는 작업 찾기
Task prevTask = loadTaskPort.findPrevOrderTaskByProcessorIdAndStatus(processorId, targetStatus, nextTask.getProcessorOrder()).orElse(null);
prevTask = loadTaskPort.findPrevOrderTaskByProcessorOrderAndStatus(processorId, targetStatus, nextTask.getProcessorOrder()).orElse(null);
long newOrder = taskOrderCalculationPolicy.calculateOrderForTop(prevTask, nextTask);
updateNewTaskOrderAndStatus(targetStatus, targetTask, newOrder);
updatedTask = updateNewTaskOrderAndStatus(targetStatus, targetTask, newOrder);
} else if (request.nextTaskId() == 0) {
Task prevTask = findByIdAndStatus(request.prevTaskId(), targetStatus);
prevTask = findByIdAndStatus(request.prevTaskId(), targetStatus);
// 해당 상태에서 바로 뒤에 있는 작업 찾기
Task nextTask = loadTaskPort.findNextOrderTaskByProcessorIdAndStatus(processorId, targetStatus, prevTask.getProcessorOrder()).orElse(null);
nextTask = loadTaskPort.findNextOrderTaskByProcessorOrderAndStatus(processorId, targetStatus, prevTask.getProcessorOrder()).orElse(null);
long newOrder = taskOrderCalculationPolicy.calculateOrderForBottom(prevTask, nextTask);
updateNewTaskOrderAndStatus(targetStatus, targetTask, newOrder);
updatedTask = updateNewTaskOrderAndStatus(targetStatus, targetTask, newOrder);
} else {
Task prevTask = findByIdAndStatus(request.prevTaskId(), targetStatus);
Task nextTask = findByIdAndStatus(request.nextTaskId(), targetStatus);
prevTask = findByIdAndStatus(request.prevTaskId(), targetStatus);
nextTask = findByIdAndStatus(request.nextTaskId(), targetStatus);
long newOrder = taskOrderCalculationPolicy.calculateNewProcessorOrder(prevTask.getProcessorOrder(), nextTask.getProcessorOrder());
updateNewTaskOrderAndStatus(targetStatus, targetTask, newOrder);
updatedTask = updateNewTaskOrderAndStatus(targetStatus, targetTask, newOrder);
}

//TODO: 최종 단계에서 주석 처리 해제
//publishNotification(targetTask, NotificationType.STATUS_SWITCHED, String.valueOf(updatedTask.getTaskStatus()));
}

/**
* 작업의 상태와 순서를 업데이트하는 메서드
*/
private void updateNewTaskOrderAndStatus(TaskStatus targetStatus, Task targetTask, long newOrder) {
private Task updateNewTaskOrderAndStatus(TaskStatus targetStatus, Task targetTask, long newOrder) {
targetTask.updateProcessorOrder(newOrder);
targetTask.updateTaskStatus(targetStatus);
taskService.upsert(targetTask);
return taskService.upsert(targetTask);
}

/**
* 순서 변경 요청의 유효성을 검증하는 메서드
*/
public void validateRequest(UpdateTaskOrderRequest request, TaskStatus targetStatus) {
// 이전 및 다음 작업 ID가 모두 0인 경우 예외 발생
if (request.prevTaskId() == 0 && request.nextTaskId() == 0) {
throw new ApplicationException(TaskErrorCode.INVALID_TASK_STATUS_TRANSITION);
}

// 타겟 상태가 유효한지 검증
if (targetStatus != null && !TaskPolicyConstants.TASK_BOARD_STATUS_FILTER.contains(targetStatus)) {
throw new ApplicationException(TaskErrorCode.INVALID_TASK_STATUS_TRANSITION);
}
}

private void publishNotification(Task task, NotificationType notificationType, String message) {
List<Member> receivers = List.of(task.getRequester(), task.getProcessor());
receivers.forEach(receiver -> {
sendNotificationService.sendPushNotification(receiver, notificationType,
task, message, null);
});
sendNotificationService.sendAgitNotification(notificationType,
task, message, null);
}

}