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 @@ -9,6 +9,7 @@
import com.back.global.rq.Rq;
import com.back.global.rsData.RsData;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.tags.Tag;
import jakarta.validation.Valid;
import lombok.RequiredArgsConstructor;
import org.springframework.data.domain.Page;
Expand All @@ -23,6 +24,7 @@
@RestController
@RequestMapping("/tasks")
@RequiredArgsConstructor
@Tag(name = "TaskController", description = "Task 컨트롤러")
public class TaskController {
private final TaskService taskService;
private final Rq rq;
Expand Down
12 changes: 8 additions & 4 deletions back/src/main/java/com/back/domain/roadmap/task/entity/Task.java
Original file line number Diff line number Diff line change
Expand Up @@ -4,27 +4,31 @@
import jakarta.persistence.*;
import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.Setter;

import java.util.ArrayList;
import java.util.List;

@Entity
@Table(name = "task")
@Getter @Setter
@Getter
@NoArgsConstructor
public class Task extends BaseEntity {
@Column(name = "name", nullable = false, unique = true)
private String name;

@OneToMany(mappedBy = "task", cascade = CascadeType.ALL)
private List<TaskAlias> aliases;
private List<TaskAlias> aliases = new ArrayList<>();

public Task(String name) {
this.name = name;
this.aliases = new ArrayList<>();
}

public void addAlias(TaskAlias alias) {
if (aliases == null) {
aliases = new ArrayList<>();
}
aliases.add(alias);
alias.setTask(this);
alias.linkToTask(this);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -4,11 +4,10 @@
import jakarta.persistence.*;
import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.Setter;

@Entity
@Table(name = "task_alias")
@Getter @Setter
@Getter
@NoArgsConstructor
public class TaskAlias extends BaseEntity {
@Column(name = "name", nullable = false, unique = true)
Expand All @@ -22,4 +21,12 @@ public TaskAlias(String name) {
this.name = name;
this.task = null; // 기본적으로 연결된 Task가 없음 (pending 상태)
}

public void linkToTask(Task task) {
this.task = task;
}

public boolean isPending() {
return this.task == null;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ public Task create(String name) {
@Transactional
public TaskAlias createAlias(Task task, String aliasName) {
TaskAlias alias = new TaskAlias(aliasName);
alias.setTask(task);
alias.linkToTask(task);
return taskAliasRepository.save(alias);
}

Expand All @@ -46,24 +46,10 @@ public List<Task> searchByKeyword(String keyword){

@Transactional
public TaskAlias createPendingAlias(String taskName){
// 1. 먼저 Alias가 존재하는지 확인 (Pending 포함)
Optional<TaskAlias> existingAliasOpt = taskAliasRepository.findByNameIgnoreCase(taskName);
if (existingAliasOpt.isPresent()) {
TaskAlias existingAlias = existingAliasOpt.get();
if (existingAlias.getTask() != null) {
throw new ServiceException("400", "이미 등록된 task의 별칭입니다.");
} else {
throw new ServiceException("400", "이미 제안된 task입니다.");
}
}
// Task나 TaskAlias에 이미 존재하는 이름인지 검증
validateNewPendingAliasName(taskName);

// 2. Alias가 없다면, Task 테이블에 직접 존재하는지 확인
Optional<Task> existingTaskOpt = taskRepository.findByNameIgnoreCase(taskName);
if(existingTaskOpt.isPresent()){
throw new ServiceException("400", "이미 등록된 task입니다.");
}

// 3. 모두 해당 없으면 새로운 pending alias 생성
// 모든 검증 통과 시 새로운 pending alias 생성
TaskAlias pendingAlias = new TaskAlias(taskName);
return taskAliasRepository.save(pendingAlias);
}
Expand All @@ -80,41 +66,26 @@ public Page<TaskAliasDto> getPendingTaskAliases(Pageable pageable) {
// Pending alias를 기존 Task와 연결
@Transactional
public TaskAlias linkPendingAlias(Long aliasId, Long taskId) {
TaskAlias pendingAlias = taskAliasRepository.findById(aliasId)
.orElseThrow(() -> new ServiceException("404", "해당 별칭이 존재하지 않습니다."));
TaskAlias pendingAlias = findPendingAliasById(aliasId);
Task task = findTaskById(taskId);

if (pendingAlias.getTask() != null) {
throw new ServiceException("400", "이미 연결된 별칭입니다.");
}

Task task = taskRepository.findById(taskId)
.orElseThrow(() -> new ServiceException("404", "해당 Task가 존재하지 않습니다."));

pendingAlias.setTask(task);
pendingAlias.linkToTask(task);
return taskAliasRepository.save(pendingAlias);
}

// Pending alias를 새로운 Task로 생성
@Transactional
public Task createTaskFromPending(Long aliasId) {
TaskAlias pendingAlias = taskAliasRepository.findById(aliasId)
.orElseThrow(() -> new ServiceException("404", "해당 별칭이 존재하지 않습니다."));

if (pendingAlias.getTask() != null) {
throw new ServiceException("400", "이미 연결된 별칭입니다.");
}
TaskAlias pendingAlias = findPendingAliasById(aliasId);

// 동일한 이름의 Task가 이미 존재하는지 확인
Optional<Task> existingTask = taskRepository.findByNameIgnoreCase(pendingAlias.getName());
if (existingTask.isPresent()) {
throw new ServiceException("400", "이미 존재하는 Task 이름입니다.");
}
validateTaskNameForCreation(pendingAlias.getName());

// 새 Task 생성
Task newTask = create(pendingAlias.getName());

// pending alias를 새 Task와 연결
pendingAlias.setTask(newTask);
pendingAlias.linkToTask(newTask);
taskAliasRepository.save(pendingAlias);

return newTask;
Expand All @@ -123,13 +94,52 @@ public Task createTaskFromPending(Long aliasId) {
// Pending alias 삭제
@Transactional
public void deletePendingAlias(Long aliasId) {
TaskAlias pendingAlias = taskAliasRepository.findById(aliasId)
TaskAlias pendingAlias = findPendingAliasById(aliasId);
taskAliasRepository.delete(pendingAlias);
}

// === 검증 로직 메서드들 ===

// TaskAlias를 ID로 조회하고 Pending 상태인지 검증
private TaskAlias findPendingAliasById(Long aliasId) {
TaskAlias alias = taskAliasRepository.findById(aliasId)
.orElseThrow(() -> new ServiceException("404", "해당 별칭이 존재하지 않습니다."));

if (pendingAlias.getTask() != null) {
throw new ServiceException("400", "연결된 별칭은 삭제할 수 없습니다.");
if (!alias.isPending()) {
throw new ServiceException("400", "이미 연결된 별칭입니다.");
}

taskAliasRepository.delete(pendingAlias);
return alias;
}

// Task를 ID로 조회
private Task findTaskById(Long taskId) {
return taskRepository.findById(taskId)
.orElseThrow(() -> new ServiceException("404", "해당 Task가 존재하지 않습니다."));
}

// Task와 TaskAlias 모두 중복 검증 (새로운 pending alias 생성 시 사용)
private void validateNewPendingAliasName(String taskName) {
// 1. TaskAlias 테이블에서 중복 확인 (Pending 포함)
Optional<TaskAlias> existingAliasOpt = taskAliasRepository.findByNameIgnoreCase(taskName);
if (existingAliasOpt.isPresent()) {
TaskAlias existingAlias = existingAliasOpt.get();
if (!existingAlias.isPending()) {
throw new ServiceException("400", "이미 등록된 Task의 별칭입니다.");
} else {
throw new ServiceException("400", "이미 제안된 Task명입니다.");
}
}

// 2. Task 테이블에서 중복 검증
validateTaskNameForCreation(taskName);
}

// 동일한 이름의 Task가 이미 존재하는지 확인 (pending alias를 새 Task로 등록할 때 사용)
private void validateTaskNameForCreation(String taskName) {
Optional<Task> existingTaskOpt = taskRepository.findByNameIgnoreCase(taskName);
if (existingTaskOpt.isPresent()) {
throw new ServiceException("400", "이미 등록된 Task명입니다.");
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -303,7 +303,7 @@ void t12() throws Exception {
.andExpect(handler().methodName("createPendingAlias"))
.andExpect(status().isBadRequest())
.andExpect(jsonPath("$.resultCode").value("400"))
.andExpect(jsonPath("$.msg").value("이미 등록된 task입니다."));
.andExpect(jsonPath("$.msg").value("이미 등록된 Task명입니다."));
}

@Test
Expand All @@ -328,7 +328,7 @@ void t13() throws Exception {
.andExpect(handler().methodName("createPendingAlias"))
.andExpect(status().isBadRequest())
.andExpect(jsonPath("$.resultCode").value("400"))
.andExpect(jsonPath("$.msg").value("이미 등록된 task의 별칭입니다."));
.andExpect(jsonPath("$.msg").value("이미 등록된 Task의 별칭입니다."));
}

@Test
Expand Down Expand Up @@ -356,7 +356,7 @@ void t14() throws Exception {
.andExpect(handler().methodName("createPendingAlias"))
.andExpect(status().isBadRequest())
.andExpect(jsonPath("$.resultCode").value("400"))
.andExpect(jsonPath("$.msg").value("이미 제안된 task입니다."));
.andExpect(jsonPath("$.msg").value("이미 제안된 Task명입니다."));
}

@Test
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -124,7 +124,7 @@ void t7() {
// When & Then
assertThatThrownBy(() -> taskService.createPendingAlias(existingTaskName))
.isInstanceOf(ServiceException.class)
.hasMessage("400 : 이미 등록된 task입니다.");
.hasMessage("400 : 이미 등록된 Task명입니다.");
}

@Test
Expand All @@ -136,7 +136,7 @@ void t8() {
// When & Then
assertThatThrownBy(() -> taskService.createPendingAlias(existingAliasName))
.isInstanceOf(ServiceException.class)
.hasMessage("400 : 이미 등록된 task의 별칭입니다.");
.hasMessage("400 : 이미 등록된 Task의 별칭입니다.");
}

@Test
Expand All @@ -149,7 +149,7 @@ void t9() {
// When & Then
assertThatThrownBy(() -> taskService.createPendingAlias(aliasName))
.isInstanceOf(ServiceException.class)
.hasMessage("400 : 이미 제안된 task입니다.");
.hasMessage("400 : 이미 제안된 Task명입니다.");
}

@Test
Expand Down Expand Up @@ -274,20 +274,6 @@ void t17() {
.hasMessage("400 : 이미 연결된 별칭입니다.");
}

@Test
@DisplayName("Pending Alias를 새로운 Task로 생성 실패 - 동일한 이름의 Task 이미 존재")
void t18() {
// Given
TaskAlias pendingAlias = taskService.createPendingAlias("중복 task"); // 먼저 pending alias 생성
taskService.create("중복 task"); // 그 다음에 동일한 이름의 Task 생성


// When & Then
assertThatThrownBy(() -> taskService.createTaskFromPending(pendingAlias.getId()))
.isInstanceOf(ServiceException.class)
.hasMessage("400 : 이미 존재하는 Task 이름입니다.");
}

@Test
@DisplayName("Pending Alias 삭제 - 성공")
void t19() {
Expand Down Expand Up @@ -322,7 +308,7 @@ void t21() {
// When & Then
assertThatThrownBy(() -> taskService.deletePendingAlias(pendingAlias.getId()))
.isInstanceOf(ServiceException.class)
.hasMessage("400 : 연결된 별칭은 삭제할 수 없습니다.");
.hasMessage("400 : 이미 연결된 별칭입니다.");
}

@Test
Expand Down