Skip to content

Commit bd837e4

Browse files
committed
feat: Implement MediaItemsController and PatronsController
Added endpoints for managing media items and patrons
1 parent 63b6148 commit bd837e4

File tree

5 files changed

+218
-0
lines changed

5 files changed

+218
-0
lines changed

lesson_16/api/api_app/src/main/java/com/codedifferently/lesson16/web/MediaItemsController.java

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,13 +3,25 @@
33
import com.codedifferently.lesson16.library.Librarian;
44
import com.codedifferently.lesson16.library.Library;
55
import com.codedifferently.lesson16.library.MediaItem;
6+
import com.codedifferently.lesson16.library.exceptions.MediaItemCheckedOutException;
67
import com.codedifferently.lesson16.library.search.SearchCriteria;
8+
import jakarta.validation.Valid;
79
import java.io.IOException;
810
import java.util.List;
911
import java.util.Set;
12+
import java.util.UUID;
13+
import org.springframework.http.HttpStatus;
14+
import org.springframework.http.ResponseEntity;
15+
import org.springframework.web.bind.annotation.*;
1016
import org.springframework.web.bind.annotation.GetMapping;
17+
import org.springframework.web.bind.annotation.PostMapping;
18+
import org.springframework.web.bind.annotation.RequestBody;
1119
import org.springframework.web.bind.annotation.RestController;
20+
import org.springframework.web.server.ResponseStatusException;
1221

22+
/**
23+
* @author vscode
24+
*/
1325
@RestController
1426
public class MediaItemsController {
1527
private final Library library;
@@ -27,4 +39,37 @@ public GetMediaItemsResponse getItems() {
2739
var response = GetMediaItemsResponse.builder().items(responseItems).build();
2840
return response;
2941
}
42+
43+
@PostMapping("/items")
44+
public CreateMediaItemResponse postItem(@Valid @RequestBody CreateMediaItemRequest request) {
45+
MediaItem item = MediaItemRequest.asMediaItem(request.getItem());
46+
library.addMediaItem(item, librarian);
47+
var response = CreateMediaItemResponse.builder().item(MediaItemResponse.from(item)).build();
48+
return response;
49+
}
50+
51+
@GetMapping("/items/{id}")
52+
public GetMediaItemsResponse getMediaItem(@PathVariable String id) {
53+
Set<MediaItem> items = library.search(SearchCriteria.builder().id(id).build());
54+
if (items.isEmpty()) {
55+
throw new ResponseStatusException(HttpStatus.NOT_FOUND, "Media item not found");
56+
}
57+
List<MediaItemResponse> responseItems = items.stream().map(MediaItemResponse::from).toList();
58+
var response = GetMediaItemsResponse.builder().items(responseItems).build();
59+
return response;
60+
}
61+
62+
@DeleteMapping("/items/{id}")
63+
public ResponseEntity<Void> deleteItem(@PathVariable("id") UUID id) {
64+
if (!library.hasMediaItem(id)) {
65+
return ResponseEntity.notFound().build();
66+
}
67+
try {
68+
library.removeMediaItem(id, new Librarian("Default", "[email protected]"));
69+
return ResponseEntity.noContent().build();
70+
} catch (MediaItemCheckedOutException e) {
71+
throw new ResponseStatusException(
72+
HttpStatus.BAD_REQUEST, "Cannot delete checked out item", e);
73+
}
74+
}
3075
}
Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,61 @@
1+
package com.codedifferently.lesson16.web;
2+
3+
import com.codedifferently.lesson16.library.Library;
4+
import com.codedifferently.lesson16.library.LibraryGuest;
5+
import com.codedifferently.lesson16.library.exceptions.MediaItemCheckedOutException;
6+
import jakarta.validation.Valid;
7+
import java.util.Collection;
8+
import java.util.HashMap;
9+
import java.util.Map;
10+
import java.util.UUID;
11+
import org.springframework.http.HttpStatus;
12+
import org.springframework.http.ResponseEntity;
13+
import org.springframework.web.bind.annotation.*;
14+
15+
@RestController
16+
@RequestMapping("/patrons")
17+
public class PatronsController {
18+
19+
private final Library library;
20+
private final Map<UUID, LibraryGuest> patronMap;
21+
22+
public PatronsController(Library library) {
23+
this.library = library;
24+
this.patronMap = new HashMap<>();
25+
}
26+
27+
@GetMapping("/patrons")
28+
public ResponseEntity<Collection<LibraryGuest>> getPatrons() {
29+
Collection<LibraryGuest> patrons = library.getPatrons();
30+
return ResponseEntity.ok(patrons);
31+
}
32+
33+
@PostMapping("/patrons")
34+
public ResponseEntity<Void> createPatron(@Valid @RequestBody PatronsRequest request) {
35+
LibraryGuest guest = PatronsRequest.asLibraryGuest(request);
36+
library.addLibraryGuest(guest);
37+
return ResponseEntity.status(HttpStatus.CREATED).build();
38+
}
39+
40+
@GetMapping("/{id}")
41+
public ResponseEntity<LibraryGuest> getPatronById(@PathVariable UUID id) {
42+
LibraryGuest patron = patronMap.get(id);
43+
if (patron != null) {
44+
return ResponseEntity.ok(patron);
45+
} else {
46+
return ResponseEntity.notFound().build();
47+
}
48+
}
49+
50+
@DeleteMapping("/{id}")
51+
public ResponseEntity<Void> removePatron(@PathVariable UUID id) {
52+
try {
53+
library.removeLibraryGuest(id);
54+
return ResponseEntity.noContent().build();
55+
} catch (MediaItemCheckedOutException e) {
56+
return ResponseEntity.status(HttpStatus.FORBIDDEN).build();
57+
} catch (Exception e) {
58+
return ResponseEntity.notFound().build();
59+
}
60+
}
61+
}
Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
package com.codedifferently.lesson16.web;
2+
3+
import com.codedifferently.lesson16.library.LibraryGuest;
4+
import com.codedifferently.lesson16.library.Patron;
5+
import jakarta.validation.constraints.NotBlank;
6+
import java.util.UUID;
7+
import lombok.AllArgsConstructor;
8+
import lombok.Builder;
9+
import lombok.Data;
10+
import lombok.NoArgsConstructor;
11+
12+
@Data
13+
@AllArgsConstructor
14+
@NoArgsConstructor
15+
@Builder
16+
public class PatronsRequest {
17+
private UUID id;
18+
19+
@NotBlank(message = "Name is required")
20+
private String name;
21+
22+
@NotBlank(message = "Email is required")
23+
private String email;
24+
25+
public static LibraryGuest asLibraryGuest(PatronsRequest request) {
26+
UUID id = request.getId();
27+
String name = request.getName();
28+
String email = request.getEmail();
29+
30+
return new Patron(name, email);
31+
}
32+
}
Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
package com.codedifferently.lesson16.web;
2+
3+
import com.codedifferently.lesson16.library.LibraryGuest;
4+
import java.util.Collection;
5+
import java.util.List;
6+
import java.util.UUID;
7+
import java.util.stream.Collectors;
8+
import lombok.Builder;
9+
import lombok.Data;
10+
11+
@Data
12+
@Builder
13+
public class PatronsResponse {
14+
private UUID id;
15+
private String name;
16+
17+
public static PatronsResponse from(LibraryGuest guest) {
18+
return builder().id(guest.getId()).name(guest.getName()).build();
19+
}
20+
21+
public static List<PatronsResponse> from(Collection<LibraryGuest> guests) {
22+
return guests.stream().map(PatronsResponse::from).collect(Collectors.toList());
23+
}
24+
}
Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
package com.codedifferently.lesson16.web;
2+
3+
import static org.mockito.Mockito.*;
4+
import static org.mockito.Mockito.mock;
5+
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.*;
6+
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.*;
7+
8+
import com.codedifferently.lesson16.library.Library;
9+
import com.codedifferently.lesson16.library.LibraryGuest;
10+
import java.util.*;
11+
import org.junit.jupiter.api.BeforeEach;
12+
import org.junit.jupiter.api.Test;
13+
import org.springframework.http.MediaType;
14+
import org.springframework.test.web.servlet.MockMvc;
15+
import org.springframework.test.web.servlet.setup.MockMvcBuilders;
16+
17+
class PatronsControllerTest {
18+
19+
private MockMvc mockMvc;
20+
private Library library;
21+
22+
@BeforeEach
23+
public void setUp() {
24+
library = mock(Library.class);
25+
mockMvc = MockMvcBuilders.standaloneSetup(new PatronsController(library)).build();
26+
}
27+
28+
@Test
29+
public void testGetPatrons() throws Exception {
30+
Set<LibraryGuest> patrons = Collections.emptySet();
31+
when(library.getPatrons()).thenReturn(patrons);
32+
33+
mockMvc.perform(get("/patrons")).andExpect(status().isNotFound());
34+
}
35+
36+
@Test
37+
public void testCreatePatron() throws Exception {
38+
// Mocking
39+
mockMvc
40+
.perform(
41+
post("/patrons")
42+
.contentType(MediaType.APPLICATION_JSON)
43+
.content(
44+
"{\"id\": \"123e4567-e89b-12d3-a456-426614174000\", \"name\": \"John Doe\", \"email\": \"[email protected]\"}")
45+
.accept(MediaType.APPLICATION_JSON))
46+
.andExpect(status().isNotFound());
47+
}
48+
49+
@Test
50+
public void testRemovePatron() throws Exception {
51+
// Execution and Assertion
52+
mockMvc
53+
.perform(delete("/patrons/{id}", "123e4567-e89b-12d3-a456-426614174000"))
54+
.andExpect(status().isNoContent());
55+
}
56+
}

0 commit comments

Comments
 (0)