diff --git a/src/main/java/org/springframework/samples/petclinic/owner/VisitController.java b/src/main/java/org/springframework/samples/petclinic/owner/VisitController.java index cc3e3ce1a09..23588a8b39a 100644 --- a/src/main/java/org/springframework/samples/petclinic/owner/VisitController.java +++ b/src/main/java/org/springframework/samples/petclinic/owner/VisitController.java @@ -41,6 +41,8 @@ @Controller class VisitController { + private static final String VIEWS_VISITS_CREATE_OR_UPDATE_FORM = "pets/createOrUpdateVisitForm"; + private final OwnerRepository owners; public VisitController(OwnerRepository owners) { @@ -61,7 +63,7 @@ public void setAllowedFields(WebDataBinder dataBinder) { */ @ModelAttribute("visit") public Visit loadPetWithVisit(@PathVariable("ownerId") int ownerId, @PathVariable("petId") int petId, - Map model) { + @PathVariable(name = "visitId", required = false) Integer visitId, Map model) { Optional optionalOwner = owners.findById(ownerId); Owner owner = optionalOwner.orElseThrow(() -> new IllegalArgumentException( "Owner not found with id: " + ownerId + ". Please ensure the ID is correct ")); @@ -74,6 +76,10 @@ public Visit loadPetWithVisit(@PathVariable("ownerId") int ownerId, @PathVariabl model.put("pet", pet); model.put("owner", owner); + if (visitId != null) { + return copyVisit(findVisit(pet, visitId)); + } + Visit visit = new Visit(); pet.addVisit(visit); return visit; @@ -83,7 +89,7 @@ public Visit loadPetWithVisit(@PathVariable("ownerId") int ownerId, @PathVariabl // called @GetMapping("/owners/{ownerId}/pets/{petId}/visits/new") public String initNewVisitForm() { - return "pets/createOrUpdateVisitForm"; + return VIEWS_VISITS_CREATE_OR_UPDATE_FORM; } // Spring MVC calls method loadPetWithVisit(...) before processNewVisitForm is @@ -92,7 +98,7 @@ public String initNewVisitForm() { public String processNewVisitForm(@ModelAttribute Owner owner, @PathVariable int petId, @Valid Visit visit, BindingResult result, RedirectAttributes redirectAttributes) { if (result.hasErrors()) { - return "pets/createOrUpdateVisitForm"; + return VIEWS_VISITS_CREATE_OR_UPDATE_FORM; } owner.addVisit(petId, visit); @@ -101,4 +107,50 @@ public String processNewVisitForm(@ModelAttribute Owner owner, @PathVariable int return "redirect:/owners/{ownerId}"; } + @GetMapping("/owners/{ownerId}/pets/{petId}/visits/{visitId}/edit") + public String initUpdateVisitForm() { + return VIEWS_VISITS_CREATE_OR_UPDATE_FORM; + } + + @PostMapping("/owners/{ownerId}/pets/{petId}/visits/{visitId}/edit") + public String processUpdateVisitForm(@ModelAttribute Owner owner, @PathVariable int petId, + @PathVariable int visitId, @Valid Visit visit, BindingResult result, + RedirectAttributes redirectAttributes) { + if (result.hasErrors()) { + return VIEWS_VISITS_CREATE_OR_UPDATE_FORM; + } + + updateVisitDescription(owner, petId, visitId, visit.getDescription()); + redirectAttributes.addFlashAttribute("message", "Visit notes have been updated"); + return "redirect:/owners/{ownerId}"; + } + + private Visit findVisit(Pet pet, int visitId) { + for (Visit visit : pet.getVisits()) { + if (visit.getId() != null && visit.getId().equals(visitId)) { + return visit; + } + } + throw new IllegalArgumentException("Visit with id " + visitId + " not found for pet with id " + pet.getId()); + } + + private Visit copyVisit(Visit source) { + Visit visit = new Visit(); + visit.setId(source.getId()); + visit.setDate(source.getDate()); + visit.setDescription(source.getDescription()); + return visit; + } + + private void updateVisitDescription(Owner owner, int petId, int visitId, String description) { + Pet pet = owner.getPet(petId); + if (pet == null) { + throw new IllegalArgumentException( + "Pet with id " + petId + " not found for owner with id " + owner.getId()); + } + Visit visit = findVisit(pet, visitId); + visit.setDescription(description); + this.owners.save(owner); + } + } diff --git a/src/main/resources/messages/messages.properties b/src/main/resources/messages/messages.properties index 19356589594..b130661af01 100644 --- a/src/main/resources/messages/messages.properties +++ b/src/main/resources/messages/messages.properties @@ -40,6 +40,8 @@ date=Date description=Description new=New addVisit=Add Visit +editVisit=Edit Visit +updateVisit=Update Visit editPet=Edit Pet ownerInformation=Owner Information visitDate=Visit Date diff --git a/src/main/resources/messages/messages_de.properties b/src/main/resources/messages/messages_de.properties index 89a08eaad26..8bdfba2f84e 100644 --- a/src/main/resources/messages/messages_de.properties +++ b/src/main/resources/messages/messages_de.properties @@ -40,6 +40,8 @@ date=Datum description=Beschreibung new=Neu addVisit=Besuch hinzufügen +editVisit=Edit Visit +updateVisit=Update Visit editPet=Haustier bearbeiten ownerInformation=Besitzerinformationen visitDate=Besuchsdatum diff --git a/src/main/resources/messages/messages_es.properties b/src/main/resources/messages/messages_es.properties index 911d7337ff3..08ae0710576 100644 --- a/src/main/resources/messages/messages_es.properties +++ b/src/main/resources/messages/messages_es.properties @@ -40,6 +40,8 @@ date=Fecha description=Descripción new=Nuevo addVisit=Agregar visita +editVisit=Edit Visit +updateVisit=Update Visit editPet=Editar mascota ownerInformation=Información del propietario visitDate=Fecha de visita diff --git a/src/main/resources/messages/messages_fa.properties b/src/main/resources/messages/messages_fa.properties index 6d0994a92e9..50b166efaa6 100644 --- a/src/main/resources/messages/messages_fa.properties +++ b/src/main/resources/messages/messages_fa.properties @@ -40,6 +40,8 @@ date=تاریخ description=توضیحات new=جدید addVisit=افزودن ویزیت +editVisit=Edit Visit +updateVisit=Update Visit editPet=ویرایش حیوان خانگی ownerInformation=اطلاعات مالک visitDate=تاریخ ویزیت diff --git a/src/main/resources/messages/messages_ko.properties b/src/main/resources/messages/messages_ko.properties index 6e2f4880aff..1101aa5231e 100644 --- a/src/main/resources/messages/messages_ko.properties +++ b/src/main/resources/messages/messages_ko.properties @@ -40,6 +40,8 @@ date=날짜 description=설명 new=새로운 addVisit=방문 추가 +editVisit=Edit Visit +updateVisit=Update Visit editPet=반려동물 수정 ownerInformation=소유자 정보 visitDate=방문 날짜 diff --git a/src/main/resources/messages/messages_pt.properties b/src/main/resources/messages/messages_pt.properties index 7eea4b9d167..7b3229bc2a7 100644 --- a/src/main/resources/messages/messages_pt.properties +++ b/src/main/resources/messages/messages_pt.properties @@ -40,6 +40,8 @@ date=Data description=Descrição new=Novo addVisit=Adicionar visita +editVisit=Edit Visit +updateVisit=Update Visit editPet=Editar animal ownerInformation=Informações do proprietário visitDate=Data da visita diff --git a/src/main/resources/messages/messages_ru.properties b/src/main/resources/messages/messages_ru.properties index f06d2cb6c03..6b90291a723 100644 --- a/src/main/resources/messages/messages_ru.properties +++ b/src/main/resources/messages/messages_ru.properties @@ -40,6 +40,8 @@ date=Дата description=Описание new=Новый addVisit=Добавить визит +editVisit=Edit Visit +updateVisit=Update Visit editPet=Редактировать питомца ownerInformation=Информация о владельце visitDate=Дата визита diff --git a/src/main/resources/messages/messages_tr.properties b/src/main/resources/messages/messages_tr.properties index 2c806f9e6c9..cedfb231856 100644 --- a/src/main/resources/messages/messages_tr.properties +++ b/src/main/resources/messages/messages_tr.properties @@ -40,6 +40,8 @@ date=Tarih description=Açıklama new=Yeni addVisit=Ziyaret Ekle +editVisit=Edit Visit +updateVisit=Update Visit editPet=Evcil Hayvanı Düzenle ownerInformation=Sahip Bilgileri visitDate=Ziyaret Tarihi diff --git a/src/main/resources/templates/owners/ownerDetails.html b/src/main/resources/templates/owners/ownerDetails.html index cc175cd1315..1632552cc05 100644 --- a/src/main/resources/templates/owners/ownerDetails.html +++ b/src/main/resources/templates/owners/ownerDetails.html @@ -62,15 +62,21 @@

Pets and Visits

Visit Date Description + + + Edit Visit + Edit Pet Add Visit + @@ -93,4 +99,4 @@

Pets and Visits

- \ No newline at end of file + diff --git a/src/main/resources/templates/pets/createOrUpdateVisitForm.html b/src/main/resources/templates/pets/createOrUpdateVisitForm.html index 4f03e12d554..2c5283f26c8 100644 --- a/src/main/resources/templates/pets/createOrUpdateVisitForm.html +++ b/src/main/resources/templates/pets/createOrUpdateVisitForm.html @@ -29,14 +29,23 @@

- + + + +
+ +
+

+
+
- +
@@ -47,13 +56,18 @@

Date Description + - - - + + + + + Edit Visit + - \ No newline at end of file + diff --git a/src/test/java/org/springframework/samples/petclinic/owner/VisitControllerTests.java b/src/test/java/org/springframework/samples/petclinic/owner/VisitControllerTests.java index bd51302ab5a..51f03b561ab 100644 --- a/src/test/java/org/springframework/samples/petclinic/owner/VisitControllerTests.java +++ b/src/test/java/org/springframework/samples/petclinic/owner/VisitControllerTests.java @@ -16,6 +16,7 @@ package org.springframework.samples.petclinic.owner; +import static org.assertj.core.api.Assertions.assertThat; import static org.mockito.BDDMockito.given; import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get; import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post; @@ -32,6 +33,7 @@ import org.springframework.test.context.bean.override.mockito.MockitoBean; import org.springframework.test.web.servlet.MockMvc; +import java.time.LocalDate; import java.util.Optional; /** @@ -49,18 +51,27 @@ class VisitControllerTests { private static final int TEST_PET_ID = 1; + private static final int TEST_VISIT_ID = 1; + @Autowired private MockMvc mockMvc; @MockitoBean private OwnerRepository owners; + private Visit visit; + @BeforeEach void init() { Owner owner = new Owner(); Pet pet = new Pet(); owner.addPet(pet); pet.setId(TEST_PET_ID); + this.visit = new Visit(); + this.visit.setId(TEST_VISIT_ID); + this.visit.setDate(LocalDate.of(2013, 1, 1)); + this.visit.setDescription("rabies shot"); + pet.addVisit(this.visit); given(this.owners.findById(TEST_OWNER_ID)).willReturn(Optional.of(owner)); } @@ -91,4 +102,38 @@ void processNewVisitFormHasErrors() throws Exception { .andExpect(view().name("pets/createOrUpdateVisitForm")); } + @Test + void initUpdateVisitForm() throws Exception { + mockMvc + .perform(get("/owners/{ownerId}/pets/{petId}/visits/{visitId}/edit", TEST_OWNER_ID, TEST_PET_ID, + TEST_VISIT_ID)) + .andExpect(status().isOk()) + .andExpect(model().attributeExists("visit")) + .andExpect(view().name("pets/createOrUpdateVisitForm")); + } + + @Test + void processUpdateVisitFormSuccess() throws Exception { + mockMvc + .perform(post("/owners/{ownerId}/pets/{petId}/visits/{visitId}/edit", TEST_OWNER_ID, TEST_PET_ID, + TEST_VISIT_ID) + .param("description", "Follow-up notes")) + .andExpect(status().is3xxRedirection()) + .andExpect(view().name("redirect:/owners/{ownerId}")); + + assertThat(this.visit.getDescription()).isEqualTo("Follow-up notes"); + } + + @Test + void processUpdateVisitFormHasErrors() throws Exception { + mockMvc + .perform(post("/owners/{ownerId}/pets/{petId}/visits/{visitId}/edit", TEST_OWNER_ID, TEST_PET_ID, + TEST_VISIT_ID) + .param("description", " ")) + .andExpect(model().attributeHasErrors("visit")) + .andExpect(model().attributeHasFieldErrors("visit", "description")) + .andExpect(status().isOk()) + .andExpect(view().name("pets/createOrUpdateVisitForm")); + } + }