|
1 | 1 | package lol.maki.dev.todo; |
2 | 2 |
|
3 | 3 | import java.net.URI; |
4 | | -import java.time.Clock; |
5 | | -import java.time.Instant; |
6 | 4 | import java.util.List; |
7 | | -import java.util.Objects; |
8 | | -import java.util.Optional; |
9 | | - |
| 5 | +import java.util.Map; |
10 | 6 | import org.springframework.http.HttpStatus; |
11 | 7 | import org.springframework.http.ResponseEntity; |
12 | 8 | import org.springframework.security.core.annotation.AuthenticationPrincipal; |
13 | 9 | import org.springframework.security.oauth2.jwt.Jwt; |
14 | | -import org.springframework.util.IdGenerator; |
15 | 10 | import org.springframework.web.bind.annotation.DeleteMapping; |
| 11 | +import org.springframework.web.bind.annotation.ExceptionHandler; |
16 | 12 | import org.springframework.web.bind.annotation.GetMapping; |
17 | 13 | import org.springframework.web.bind.annotation.PatchMapping; |
18 | 14 | import org.springframework.web.bind.annotation.PathVariable; |
19 | 15 | import org.springframework.web.bind.annotation.PostMapping; |
20 | 16 | import org.springframework.web.bind.annotation.RequestBody; |
21 | 17 | import org.springframework.web.bind.annotation.RequestMapping; |
22 | 18 | import org.springframework.web.bind.annotation.RestController; |
23 | | -import org.springframework.web.server.ResponseStatusException; |
24 | 19 | import org.springframework.web.util.UriComponentsBuilder; |
25 | 20 |
|
26 | 21 | @RestController |
27 | 22 | @RequestMapping(path = "/todos") |
28 | 23 | public class TodoController { |
29 | 24 |
|
30 | | - private final TodoRepository todoRepository; |
31 | | - |
32 | | - private final IdGenerator idGenerator; |
33 | | - |
34 | | - private final Clock clock; |
| 25 | + private final TodoService todoService; |
35 | 26 |
|
36 | | - public TodoController(TodoRepository todoRepository, IdGenerator idGenerator, Clock clock) { |
37 | | - this.todoRepository = todoRepository; |
38 | | - this.idGenerator = idGenerator; |
39 | | - this.clock = clock; |
| 27 | + public TodoController(TodoService todoService) { |
| 28 | + this.todoService = todoService; |
40 | 29 | } |
41 | 30 |
|
42 | 31 | @GetMapping(path = "") |
43 | 32 | public ResponseEntity<List<Todo>> getTodos() { |
44 | | - List<Todo> todos = this.todoRepository.findAll(); |
| 33 | + List<Todo> todos = this.todoService.getTodos(); |
45 | 34 | return ResponseEntity.ok(todos); |
46 | 35 | } |
47 | 36 |
|
48 | 37 | @GetMapping(path = "/{todoId}") |
49 | 38 | public ResponseEntity<Todo> getTodo(@PathVariable("todoId") String todoId) { |
50 | | - Todo todo = this.todoRepository.findById(todoId) |
51 | | - .orElseThrow(() -> new ResponseStatusException(HttpStatus.NOT_FOUND, |
52 | | - "Todo not found: todoId=%s".formatted(todoId))); |
| 39 | + Todo todo = this.todoService.getTodo(todoId); |
53 | 40 | return ResponseEntity.ok(todo); |
54 | 41 | } |
55 | 42 |
|
56 | 43 | @PostMapping(path = "") |
57 | 44 | public ResponseEntity<Todo> postTodos(@RequestBody Todo todo, @AuthenticationPrincipal Jwt jwt, |
58 | 45 | UriComponentsBuilder builder) { |
59 | | - Instant now = this.clock.instant(); |
60 | 46 | String email = jwt.getClaimAsString("email"); |
61 | | - Todo initialized = TodoBuilder.from(todo) |
62 | | - .todoId(this.idGenerator.generateId().toString()) |
63 | | - .createdBy(email) |
64 | | - .createdAt(now) |
65 | | - .updatedBy(email) |
66 | | - .updatedAt(now) |
67 | | - .build(); |
68 | | - Todo created = this.todoRepository.save(initialized); |
| 47 | + Todo created = this.todoService.create(todo.todoTitle(), email); |
69 | 48 | URI uri = builder.pathSegment("todos", created.todoId()).build().toUri(); |
70 | 49 | return ResponseEntity.created(uri).body(created); |
71 | 50 | } |
72 | 51 |
|
73 | 52 | @PatchMapping(path = "/{todoId}") |
74 | 53 | public ResponseEntity<Todo> patchTodo(@PathVariable("todoId") String todoId, @RequestBody Todo todo, |
75 | 54 | @AuthenticationPrincipal Jwt jwt) { |
76 | | - Optional<Todo> updated = this.todoRepository.findById(todoId).map(t -> { |
77 | | - TodoBuilder builder = TodoBuilder.from(t); |
78 | | - boolean touched = false; |
79 | | - if (todo.todoTitle() != null) { |
80 | | - builder.todoTitle(todo.todoTitle()); |
81 | | - touched = true; |
82 | | - } |
83 | | - if (!Objects.equals(todo.finished(), t.finished())) { |
84 | | - builder.finished(todo.finished()); |
85 | | - touched = true; |
86 | | - } |
87 | | - if (touched) { |
88 | | - builder.updatedBy(jwt.getClaimAsString("email")); |
89 | | - builder.updatedAt(this.clock.instant()); |
90 | | - } |
91 | | - return builder.build(); |
92 | | - }).map(this.todoRepository::save); |
93 | | - return ResponseEntity.of(updated); |
| 55 | + String email = jwt.getClaimAsString("email"); |
| 56 | + Todo updated = this.todoService.update(todoId, todo.todoTitle(), todo.finished(), email); |
| 57 | + return ResponseEntity.ok(updated); |
94 | 58 | } |
95 | 59 |
|
96 | 60 | @DeleteMapping(path = "/{todoId}") |
97 | 61 | public ResponseEntity<Void> deleteTodo(@PathVariable("todoId") String todoId) { |
98 | | - this.todoRepository.deleteById(todoId); |
| 62 | + this.todoService.deleteById(todoId); |
99 | 63 | return ResponseEntity.noContent().build(); |
100 | 64 | } |
101 | 65 |
|
| 66 | + @ExceptionHandler(TodoService.NotFoundException.class) |
| 67 | + public ResponseEntity<?> handleNotFound(TodoService.NotFoundException e) { |
| 68 | + return ResponseEntity.status(HttpStatus.NOT_FOUND).body(Map.of("message", e.getMessage())); |
| 69 | + } |
| 70 | + |
102 | 71 | } |
0 commit comments