diff --git a/lesson_16/api/api_app/src/main/java/com/codedifferently/lesson16/web/MediaItemsController.java b/lesson_16/api/api_app/src/main/java/com/codedifferently/lesson16/web/MediaItemsController.java index cae5ff06..611e7682 100644 --- a/lesson_16/api/api_app/src/main/java/com/codedifferently/lesson16/web/MediaItemsController.java +++ b/lesson_16/api/api_app/src/main/java/com/codedifferently/lesson16/web/MediaItemsController.java @@ -3,15 +3,20 @@ import com.codedifferently.lesson16.library.Librarian; import com.codedifferently.lesson16.library.Library; import com.codedifferently.lesson16.library.MediaItem; +import com.codedifferently.lesson16.library.exceptions.MediaItemCheckedOutException; import com.codedifferently.lesson16.library.search.SearchCriteria; +import jakarta.validation.Valid; import java.io.IOException; import java.util.List; import java.util.Set; -import org.springframework.web.bind.annotation.GetMapping; -import org.springframework.web.bind.annotation.RestController; +import java.util.UUID; +import org.springframework.http.HttpStatus; +import org.springframework.http.ResponseEntity; +import org.springframework.web.bind.annotation.*; @RestController public class MediaItemsController { + private final Library library; private final Librarian librarian; @@ -27,4 +32,39 @@ public GetMediaItemsResponse getItems() { var response = GetMediaItemsResponse.builder().items(responseItems).build(); return response; } + + @PostMapping("/items") + public CreateMediaItemResponse createItem(@Valid @RequestBody CreateMediaItemRequest request) { + MediaItem item = MediaItemRequest.asMediaItem(request.getItem()); + library.addMediaItem(item, librarian); + return CreateMediaItemResponse.builder().item(MediaItemResponse.from(item)).build(); + } + + @GetMapping("/items/{id}") + public ResponseEntity getMediaItem(@PathVariable UUID id) { + SearchCriteria criteria = SearchCriteria.builder().id(id.toString()).build(); + Set items = library.search(criteria); + if (!items.isEmpty()) { + MediaItemResponse response = MediaItemResponse.from(items.iterator().next()); + return ResponseEntity.ok(response); + } else { + return ResponseEntity.notFound().build(); + } + } + + @DeleteMapping("/items/{id}") + public ResponseEntity deleteItem(@PathVariable UUID id) { + SearchCriteria criteria = SearchCriteria.builder().id(id.toString()).build(); + Set items = library.search(criteria); + if (!items.isEmpty()) { + try { + library.removeMediaItem(id, new Librarian("Default", "librarian@example.com")); + return ResponseEntity.noContent().build(); + } catch (MediaItemCheckedOutException e) { + return ResponseEntity.status(HttpStatus.FORBIDDEN).build(); + } + } else { + return ResponseEntity.notFound().build(); + } + } } diff --git a/lesson_16/api/api_app/src/main/java/com/codedifferently/lesson16/web/PatronsController.java b/lesson_16/api/api_app/src/main/java/com/codedifferently/lesson16/web/PatronsController.java new file mode 100644 index 00000000..42cd4cd0 --- /dev/null +++ b/lesson_16/api/api_app/src/main/java/com/codedifferently/lesson16/web/PatronsController.java @@ -0,0 +1,51 @@ +package com.codedifferently.lesson16.web; + +import com.codedifferently.lesson16.library.Library; +import com.codedifferently.lesson16.library.LibraryGuest; +import com.codedifferently.lesson16.library.exceptions.MediaItemCheckedOutException; +import jakarta.validation.Valid; +import java.util.Collection; +import java.util.UUID; +import org.springframework.http.HttpStatus; +import org.springframework.http.ResponseEntity; +import org.springframework.web.bind.annotation.*; + +@RestController +@RequestMapping("/patrons") +public class PatronsController { + + private final Library library; + + public PatronsController(Library library) { + this.library = library; + } + + @GetMapping + public ResponseEntity> getPatrons() { + Collection patrons = library.getPatrons(); + return ResponseEntity.ok(patrons); + } + + @PostMapping + public ResponseEntity createPatron(@Valid @RequestBody PatronsRequest request) { + LibraryGuest guest = PatronsRequest.asLibraryGuest(request); + library.addLibraryGuest(guest); + return ResponseEntity.status(HttpStatus.CREATED).build(); + } + + @GetMapping("/{id}") + public ResponseEntity> getPatron() { + Collection patron = library.getPatrons(); + return ResponseEntity.ok(patron); + } + + @DeleteMapping("/{id}") + public ResponseEntity removePatron(@PathVariable UUID id) { + try { + library.removeLibraryGuest(id); + return ResponseEntity.noContent().build(); + } catch (MediaItemCheckedOutException e) { + return ResponseEntity.status(HttpStatus.FORBIDDEN).build(); + } + } +} diff --git a/lesson_16/api/api_app/src/main/java/com/codedifferently/lesson16/web/PatronsRequest.java b/lesson_16/api/api_app/src/main/java/com/codedifferently/lesson16/web/PatronsRequest.java new file mode 100644 index 00000000..f82e2d39 --- /dev/null +++ b/lesson_16/api/api_app/src/main/java/com/codedifferently/lesson16/web/PatronsRequest.java @@ -0,0 +1,32 @@ +package com.codedifferently.lesson16.web; + +import com.codedifferently.lesson16.library.LibraryGuest; +import com.codedifferently.lesson16.library.Patron; +import jakarta.validation.constraints.NotBlank; +import java.util.UUID; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; + +@Data +@AllArgsConstructor +@NoArgsConstructor +@Builder +public class PatronsRequest { + private UUID id; + + @NotBlank(message = "Name is required") + private String name; + + @NotBlank(message = "Email is required") + private String email; + + public static LibraryGuest asLibraryGuest(PatronsRequest request) { + UUID id = request.getId(); + String name = request.getName(); + String email = request.getEmail(); + + return new Patron(name, email); + } +} diff --git a/lesson_16/api/api_app/src/main/java/com/codedifferently/lesson16/web/PatronsResponse.java b/lesson_16/api/api_app/src/main/java/com/codedifferently/lesson16/web/PatronsResponse.java new file mode 100644 index 00000000..76e27b4d --- /dev/null +++ b/lesson_16/api/api_app/src/main/java/com/codedifferently/lesson16/web/PatronsResponse.java @@ -0,0 +1,24 @@ +package com.codedifferently.lesson16.web; + +import com.codedifferently.lesson16.library.LibraryGuest; +import java.util.Collection; +import java.util.List; +import java.util.UUID; +import java.util.stream.Collectors; +import lombok.Builder; +import lombok.Data; + +@Data +@Builder +public class PatronsResponse { + private UUID id; + private String name; + + public static PatronsResponse from(LibraryGuest guest) { + return PatronsResponse.builder().id(guest.getId()).name(guest.getName()).build(); + } + + public static List from(Collection guests) { + return guests.stream().map(PatronsResponse::from).collect(Collectors.toList()); + } +} diff --git a/lesson_16/api/api_app/src/test/java/com/codedifferently/lesson16/web/PatronsControllerTest.java b/lesson_16/api/api_app/src/test/java/com/codedifferently/lesson16/web/PatronsControllerTest.java new file mode 100644 index 00000000..db00592c --- /dev/null +++ b/lesson_16/api/api_app/src/test/java/com/codedifferently/lesson16/web/PatronsControllerTest.java @@ -0,0 +1,71 @@ +package com.codedifferently.lesson16.web; + +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.when; +import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.*; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.*; + +import com.codedifferently.lesson16.library.Library; +import com.codedifferently.lesson16.library.LibraryGuest; +import java.util.Collections; +import java.util.Set; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.springframework.http.MediaType; +import org.springframework.test.web.servlet.MockMvc; +import org.springframework.test.web.servlet.setup.MockMvcBuilders; + +public class PatronsControllerTest { + + private MockMvc mockMvc; + private Library library; + + @BeforeEach + public void setUp() { + library = mock(Library.class); + mockMvc = MockMvcBuilders.standaloneSetup(new PatronsController(library)).build(); + } + + @Test + public void testGetPatrons() throws Exception { + // Mocking + Set patrons = Collections.emptySet(); // Assuming no patrons for simplicity + when(library.getPatrons()).thenReturn(patrons); + + // Execution and Assertion + mockMvc + .perform(get("/patrons")) + .andExpect(status().isOk()) + .andExpect(content().contentType(MediaType.APPLICATION_JSON)); + } + + @Test + public void testCreatePatron() throws Exception { + // Mocking + mockMvc + .perform( + post("/patrons") + .contentType(MediaType.APPLICATION_JSON) + .content( + "{\"id\": \"123e4567-e89b-12d3-a456-426614174000\", \"name\": \"John Doe\", \"email\": \"john@example.com\"}") + .accept(MediaType.APPLICATION_JSON)) + .andExpect(status().isCreated()); + } + + @Test + public void testRemovePatron() throws Exception { + // Execution and Assertion + mockMvc + .perform(delete("/patrons/{id}", "123e4567-e89b-12d3-a456-426614174000")) + .andExpect(status().isNoContent()); + } + + @Test + void testGetPatronById() throws Exception { + mockMvc + .perform( + get("/patrons/{id}", "31616162-3831-3832-2d34-3334352d3465") + .contentType(MediaType.APPLICATION_JSON)) + .andExpect(status().isOk()); + } +}