Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -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) {
Expand All @@ -61,7 +63,7 @@ public void setAllowedFields(WebDataBinder dataBinder) {
*/
@ModelAttribute("visit")
public Visit loadPetWithVisit(@PathVariable("ownerId") int ownerId, @PathVariable("petId") int petId,
Map<String, Object> model) {
@PathVariable(name = "visitId", required = false) Integer visitId, Map<String, Object> model) {
Optional<Owner> optionalOwner = owners.findById(ownerId);
Owner owner = optionalOwner.orElseThrow(() -> new IllegalArgumentException(
"Owner not found with id: " + ownerId + ". Please ensure the ID is correct "));
Expand All @@ -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;
Expand All @@ -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
Expand All @@ -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);
Expand All @@ -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);
}

}
2 changes: 2 additions & 0 deletions src/main/resources/messages/messages.properties
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
2 changes: 2 additions & 0 deletions src/main/resources/messages/messages_de.properties
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
2 changes: 2 additions & 0 deletions src/main/resources/messages/messages_es.properties
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
2 changes: 2 additions & 0 deletions src/main/resources/messages/messages_fa.properties
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,8 @@ date=تاریخ
description=توضیحات
new=جدید
addVisit=افزودن ویزیت
editVisit=Edit Visit
updateVisit=Update Visit
editPet=ویرایش حیوان خانگی
ownerInformation=اطلاعات مالک
visitDate=تاریخ ویزیت
Expand Down
2 changes: 2 additions & 0 deletions src/main/resources/messages/messages_ko.properties
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,8 @@ date=날짜
description=설명
new=새로운
addVisit=방문 추가
editVisit=Edit Visit
updateVisit=Update Visit
editPet=반려동물 수정
ownerInformation=소유자 정보
visitDate=방문 날짜
Expand Down
2 changes: 2 additions & 0 deletions src/main/resources/messages/messages_pt.properties
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
2 changes: 2 additions & 0 deletions src/main/resources/messages/messages_ru.properties
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,8 @@ date=Дата
description=Описание
new=Новый
addVisit=Добавить визит
editVisit=Edit Visit
updateVisit=Update Visit
editPet=Редактировать питомца
ownerInformation=Информация о владельце
visitDate=Дата визита
Expand Down
2 changes: 2 additions & 0 deletions src/main/resources/messages/messages_tr.properties
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
8 changes: 7 additions & 1 deletion src/main/resources/templates/owners/ownerDetails.html
Original file line number Diff line number Diff line change
Expand Up @@ -62,15 +62,21 @@ <h2 th:text="#{petsAndVisits}">Pets and Visits</h2>
<tr>
<th th:text="#{visitDate}">Visit Date</th>
<th th:text="#{description}">Description</th>
<th></th>
</tr>
</thead>
<tr th:each="visit : ${pet.visits}">
<td th:text="${#temporals.format(visit.date, 'yyyy-MM-dd')}"></td>
<td th:text="${visit?.description}"></td>
<td>
<a th:href="@{__${owner.id}__/pets/__${pet.id}__/visits/__${visit.id}__/edit}"
th:text="#{editVisit}">Edit Visit</a>
</td>
</tr>
<tr>
<td><a th:href="@{__${owner.id}__/pets/__${pet.id}__/edit}" th:text="#{editPet}">Edit Pet</a></td>
<td><a th:href="@{__${owner.id}__/pets/__${pet.id}__/visits/new}" th:text="#{addVisit}">Add Visit</a></td>
<td></td>
</tr>
</table>
</td>
Expand All @@ -93,4 +99,4 @@ <h2 th:text="#{petsAndVisits}">Pets and Visits</h2>
</body>


</html>
</html>
26 changes: 20 additions & 6 deletions src/main/resources/templates/pets/createOrUpdateVisitForm.html
Original file line number Diff line number Diff line change
Expand Up @@ -29,14 +29,23 @@ <h2>

<form th:object="${visit}" class="form-horizontal" method="post">
<div class="form-group has-feedback">
<input th:replace="~{fragments/inputField :: input ('Date', 'date', 'date')}" />
<th:block th:if="${visit['new']}">
<input th:replace="~{fragments/inputField :: input ('Date', 'date', 'date')}" />
</th:block>
<div class="form-group" th:unless="${visit['new']}">
<label class="col-sm-2 control-label" th:text="#{date}">Date</label>
<div class="col-sm-10">
<p class="form-control-static" th:text="${#temporals.format(visit.date, 'yyyy-MM-dd')}"></p>
</div>
</div>
<input th:replace="~{fragments/inputField :: input ('Description', 'description', 'text')}" />
</div>

<div class="form-group">
<div class="col-sm-offset-2 col-sm-10">
<input type="hidden" name="petId" th:value="${pet.id}" />
<button class="btn btn-primary" type="submit" th:text="#{addVisit}">Add Visit</button>
<button th:with="text=${visit['new']} ? #{addVisit} : #{updateVisit}" class="btn btn-primary" type="submit"
th:text="${text}">Add Visit</button>
</div>
</div>
</form>
Expand All @@ -47,13 +56,18 @@ <h2>
<tr>
<th th:text="#{date}">Date</th>
<th th:text="#{description}">Description</th>
<th></th>
</tr>
<tr th:if="${!visit['new']}" th:each="visit : ${pet.visits}">
<td th:text="${#temporals.format(visit.date, 'yyyy-MM-dd')}"></td>
<td th:text=" ${visit.description}"></td>
<tr th:if="${!previousVisit['new']}" th:each="previousVisit : ${pet.visits}">
<td th:text="${#temporals.format(previousVisit.date, 'yyyy-MM-dd')}"></td>
<td th:text=" ${previousVisit.description}"></td>
<td>
<a th:href="@{/owners/{ownerId}/pets/{petId}/visits/{visitId}/edit(ownerId=${owner.id},petId=${pet.id},visitId=${previousVisit.id})}"
th:text="#{editVisit}">Edit Visit</a>
</td>
</tr>
</table>

</body>

</html>
</html>
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -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;

/**
Expand All @@ -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));
}

Expand Down Expand Up @@ -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"));
}

}