diff --git a/src/main/java/org/idiot/yesslave/YesSlaveApplication.java b/src/main/java/org/idiot/yesslave/YesSlaveApplication.java index 45ef084..194f8e9 100644 --- a/src/main/java/org/idiot/yesslave/YesSlaveApplication.java +++ b/src/main/java/org/idiot/yesslave/YesSlaveApplication.java @@ -2,6 +2,7 @@ import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; +import org.springframework.data.jpa.repository.config.EnableJpaAuditing; @SpringBootApplication public class YesSlaveApplication { diff --git a/src/main/java/org/idiot/yesslave/global/exception/ErrorCode.java b/src/main/java/org/idiot/yesslave/global/exception/ErrorCode.java new file mode 100644 index 0000000..cc5ac7e --- /dev/null +++ b/src/main/java/org/idiot/yesslave/global/exception/ErrorCode.java @@ -0,0 +1,15 @@ +package org.idiot.yesslave.global.exception; + +import lombok.Getter; + +public enum ErrorCode { + ID_NOT_FOUND("해당 ID를 찾을 수 없습니다."), + ID_DELETE("삭제된 ID입니다."); + + @Getter + private String message; + + ErrorCode(String message) { + this.message = message; + } +} diff --git a/src/main/java/org/idiot/yesslave/global/exception/TodoIdHandler.java b/src/main/java/org/idiot/yesslave/global/exception/TodoIdHandler.java new file mode 100644 index 0000000..5510988 --- /dev/null +++ b/src/main/java/org/idiot/yesslave/global/exception/TodoIdHandler.java @@ -0,0 +1,14 @@ +package org.idiot.yesslave.global.exception; + +import lombok.Getter; + +public class TodoIdHandler extends RuntimeException { + + @Getter + private final ErrorCode errorCode; + + public TodoIdHandler(ErrorCode errorCode) { + super(errorCode.getMessage()); + this.errorCode = errorCode; + } +} diff --git a/src/main/java/org/idiot/yesslave/todo/application/TodoService.java b/src/main/java/org/idiot/yesslave/todo/application/TodoService.java new file mode 100644 index 0000000..6a050e9 --- /dev/null +++ b/src/main/java/org/idiot/yesslave/todo/application/TodoService.java @@ -0,0 +1,60 @@ +package org.idiot.yesslave.todo.application; + +import lombok.RequiredArgsConstructor; +import org.idiot.yesslave.global.exception.TodoIdHandler; +import org.idiot.yesslave.global.exception.ErrorCode; +import org.idiot.yesslave.todo.domain.Todo; +import org.idiot.yesslave.todo.dto.SaveDto; +import org.idiot.yesslave.todo.dto.UpdateDto; +import org.idiot.yesslave.todo.repository.TodoRepository; +import org.springframework.stereotype.Service; + +import javax.transaction.Transactional; + +@Service +@RequiredArgsConstructor +public class TodoService { + private final TodoRepository todoRepository; + + @Transactional + public void save(SaveDto saveDto) { + todoRepository.save(Todo.builder() + .todo(saveDto.getTodo()) + .build()); + } + + @Transactional + public void update(Long id, UpdateDto updateDto) { + Todo todo = existId(id); + checkDeleteStatus(todo); + todo.update(updateDto.getTodo()); + } + + @Transactional + public boolean changeCheck(Long id) { + Todo todo = existId(id); + checkDeleteStatus(todo); + todo.changeCheck(!todo.isTodoCheck()); + return todo.isTodoCheck(); + } + + @Transactional + public void delete(Long id) { + Todo todo = existId(id); + checkDeleteStatus(todo); + todo.delete(); + } + + private void checkDeleteStatus(Todo todo) { + if (todo.isDelete()) { + throw new TodoIdHandler(ErrorCode.ID_DELETE); + } + } + + public Todo existId(Long id) { + Todo todo = todoRepository.findById(id) + .orElseThrow(() -> new TodoIdHandler(ErrorCode.ID_NOT_FOUND)); + return todo; + } + +} diff --git a/src/main/java/org/idiot/yesslave/todo/domain/Todo.java b/src/main/java/org/idiot/yesslave/todo/domain/Todo.java new file mode 100644 index 0000000..2e7e47b --- /dev/null +++ b/src/main/java/org/idiot/yesslave/todo/domain/Todo.java @@ -0,0 +1,56 @@ +package org.idiot.yesslave.todo.domain; + +import lombok.*; +import org.hibernate.annotations.Comment; +import org.idiot.yesslave.global.jpa.AuditInformation; + +import javax.persistence.Column; +import javax.persistence.Entity; +import javax.persistence.GeneratedValue; +import javax.persistence.GenerationType; +import javax.persistence.Id; +import javax.persistence.Table; + + +@Entity +@Getter +@Table(name = "TODO") +@NoArgsConstructor(access = AccessLevel.PROTECTED) +public class Todo extends AuditInformation { + + @Id + @GeneratedValue(strategy = GenerationType.IDENTITY) + @Column(name = "ID", nullable = false) + private Long id; + + @Column(name = "TODO", nullable = false) + @Comment("다짐") + private String todo; + + @Column(name = "TODO_CHECK", nullable = false) + @Comment("실행여부") + private boolean todoCheck = false; + + @Column(name = "DELETE", nullable = false) + @Comment("삭제여부") + private boolean delete = false; + + + @Builder + public Todo(String todo) { + this.todo = todo; + } + + + public void changeCheck(boolean todoCheck) { + this.todoCheck = todoCheck; + } + + public void update(String todo) { + this.todo = todo; + } + public void delete () { + delete = true; + } + +} diff --git a/src/main/java/org/idiot/yesslave/todo/dto/SaveDto.java b/src/main/java/org/idiot/yesslave/todo/dto/SaveDto.java new file mode 100644 index 0000000..125f9fb --- /dev/null +++ b/src/main/java/org/idiot/yesslave/todo/dto/SaveDto.java @@ -0,0 +1,18 @@ +package org.idiot.yesslave.todo.dto; + +import lombok.AccessLevel; +import lombok.Builder; +import lombok.Getter; +import lombok.NoArgsConstructor; + +@Getter +@NoArgsConstructor(access = AccessLevel.PROTECTED) +// cannot deserialize from Object value (no delegate- or property-based Creator)에러로 인해 기본 생성자 필요 +public class SaveDto { + private String todo; + @Builder + public SaveDto(String todo) { + this.todo = todo; + } + +} diff --git a/src/main/java/org/idiot/yesslave/todo/dto/UpdateDto.java b/src/main/java/org/idiot/yesslave/todo/dto/UpdateDto.java new file mode 100644 index 0000000..a6bfa95 --- /dev/null +++ b/src/main/java/org/idiot/yesslave/todo/dto/UpdateDto.java @@ -0,0 +1,15 @@ +package org.idiot.yesslave.todo.dto; + +import lombok.AccessLevel; +import lombok.Getter; +import lombok.NoArgsConstructor; + +@Getter +@NoArgsConstructor(access = AccessLevel.PROTECTED) +public class UpdateDto { + private String todo; + + public UpdateDto(String todo) { + this.todo = todo; + } +} diff --git a/src/main/java/org/idiot/yesslave/todo/repository/TodoRepository.java b/src/main/java/org/idiot/yesslave/todo/repository/TodoRepository.java new file mode 100644 index 0000000..d7cc2de --- /dev/null +++ b/src/main/java/org/idiot/yesslave/todo/repository/TodoRepository.java @@ -0,0 +1,7 @@ +package org.idiot.yesslave.todo.repository; + +import org.idiot.yesslave.todo.domain.Todo; +import org.springframework.data.jpa.repository.JpaRepository; + +public interface TodoRepository extends JpaRepository{ +} diff --git a/src/main/java/org/idiot/yesslave/todo/ui/TodoController.java b/src/main/java/org/idiot/yesslave/todo/ui/TodoController.java new file mode 100644 index 0000000..9ce5ba0 --- /dev/null +++ b/src/main/java/org/idiot/yesslave/todo/ui/TodoController.java @@ -0,0 +1,40 @@ +package org.idiot.yesslave.todo.ui; + +import lombok.RequiredArgsConstructor; +import org.idiot.yesslave.todo.application.TodoService; +import org.idiot.yesslave.todo.dto.SaveDto; +import org.idiot.yesslave.todo.dto.UpdateDto; +import org.springframework.http.ResponseEntity; +import org.springframework.web.bind.annotation.*; + +@RestController +@RequestMapping("/todo") +@RequiredArgsConstructor +public class TodoController { + + private final TodoService todoService; + + @PostMapping + public ResponseEntity todoSave(@RequestBody SaveDto saveDto) { + todoService.save(saveDto); + return ResponseEntity.ok("Todo save successfully"); + } + + @PatchMapping("/{id}") + public ResponseEntity todoUpdate(@PathVariable Long id, @RequestBody UpdateDto updateDto) { + todoService.update(id, updateDto); + return ResponseEntity.ok("Todo updated successfully"); + } + + @PostMapping("/{id}") + public boolean changeCheck(@PathVariable Long id) { + return todoService.changeCheck(id); + } + + @DeleteMapping("/{id}") + public ResponseEntity delete(@PathVariable Long id) { + todoService.delete(id); + return ResponseEntity.ok("Todo delete successfully"); + } + +} diff --git a/src/main/resources/application.yml b/src/main/resources/application.yml index f3f9fb7..e6034a2 100644 --- a/src/main/resources/application.yml +++ b/src/main/resources/application.yml @@ -20,4 +20,6 @@ spring: add-mappings: false mvc: throw-exception-if-no-handler-found: true - \ No newline at end of file + main: + allow-bean-definition-overriding: true + diff --git a/src/test/java/org/idiot/yesslave/todo/ui/TodoControllerTest.java b/src/test/java/org/idiot/yesslave/todo/ui/TodoControllerTest.java new file mode 100644 index 0000000..830c576 --- /dev/null +++ b/src/test/java/org/idiot/yesslave/todo/ui/TodoControllerTest.java @@ -0,0 +1,127 @@ +package org.idiot.yesslave.todo.ui; + +import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.*; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.content; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; + +import com.fasterxml.jackson.databind.ObjectMapper; + +import org.assertj.core.api.Assertions; +import org.idiot.yesslave.todo.domain.Todo; +import org.idiot.yesslave.todo.dto.SaveDto; +import org.idiot.yesslave.todo.repository.TodoRepository; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.http.MediaType; +import org.springframework.test.web.servlet.MockMvc; + + +@SpringBootTest +@AutoConfigureMockMvc +public class TodoControllerTest { + @Autowired + ObjectMapper mapper; + + @Autowired + MockMvc mvc; + + @Autowired + private TodoRepository todoRepository; + + private static final String BASE_URL = "/todo"; + + @Test + @DisplayName("저장 테스트") + void save_test() throws Exception { + //given + String text = "Test schedule"; + + //when + String body = mapper.writeValueAsString( + SaveDto.builder() + .todo(text) + .build() + ); + + //then + mvc.perform(post(BASE_URL) + .content(body) //HTTP Body에 데이터를 담는다 + .contentType(MediaType.APPLICATION_JSON) //보내는 데이터의 타입을 명시 + ) + .andExpect(status().isOk()) + .andExpect(content().string("Todo save successfully")); + } + + @Test + @DisplayName("수정 테스트") + void patch_test() throws Exception { + + //given + String text = "Test schedule"; + String change_text = "Change test schedule"; + + //when + todoRepository.save(Todo.builder() + .todo(text) + .build()); + + String body = mapper.writeValueAsString( + SaveDto.builder() + .todo(change_text) + .build() + ); + + //then + mvc.perform(patch(BASE_URL + "/2") + .contentType(MediaType.APPLICATION_JSON) + .content(body) + ) + .andExpect(status().isOk()) + .andExpect(content().string("Todo updated successfully")); + + } + + @Test + @DisplayName("체크 변경 테스트") + void change_check_test() throws Exception { + + //given + String text = "Test schedule"; + + //when + todoRepository.save(Todo.builder() + .todo(text) + .build()); + + //then + mvc.perform(post(BASE_URL + "/2") + .contentType(MediaType.APPLICATION_JSON) + ) + .andExpect(status().isOk()) + .andExpect(content().string("Todo change successfully")); + + } + + @DisplayName("삭제 테스트") + @Test + public void delete_Test() throws Exception { + + //given + String text = "Test schedule"; + + //when + todoRepository.save(Todo.builder() + .todo(text) + .build()); + + //then + mvc.perform(delete(BASE_URL + "/1")) + .andExpect(status().isOk()) + .andExpect(content().string("Todo delete successfully")); + + Assertions.assertThat(todoRepository.findById(1L).isEmpty()); + } +} diff --git a/src/test/java/org/idiot/yesslave/worktimer/ui/WorkTimerControllerTest.java b/src/test/java/org/idiot/yesslave/worktimer/ui/WorkTimerControllerTest.java index 9082829..8d8274a 100644 --- a/src/test/java/org/idiot/yesslave/worktimer/ui/WorkTimerControllerTest.java +++ b/src/test/java/org/idiot/yesslave/worktimer/ui/WorkTimerControllerTest.java @@ -29,7 +29,7 @@ import static org.springframework.test.web.servlet.result.MockMvcResultHandlers.print; -@WebMvcTest +@WebMvcTest(WorkTimerController.class) @ExtendWith(SpringExtension.class) class WorkTimerControllerTest {