Skip to content

Commit

Permalink
Added ability to add or update pet. closes #56
Browse files Browse the repository at this point in the history
  • Loading branch information
Priyanshu-git committed Jun 11, 2021
1 parent 65dd52c commit 079f440
Show file tree
Hide file tree
Showing 7 changed files with 323 additions and 6 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,9 @@ public Owner(Long id, String firstName, String lastName, String address, String
this.address = address;
this.city = city;
this.telephone = telephone;
this.pets = pets;
if (pets != null) {
this.pets = pets;
}
}

@Column(name = "address")
Expand All @@ -37,5 +39,22 @@ public Owner(Long id, String firstName, String lastName, String address, String
@OneToMany(cascade = CascadeType.ALL, mappedBy = "owner")
private Set<Pet> pets = new HashSet<>();

public Pet getPet(String name) {
return getPet(name, false);
}

public Pet getPet(String name, boolean ignoreNew) {
name = name.toLowerCase();
for (Pet pet : pets) {
if (!ignoreNew || !pet.isNew()) {
String compName = pet.getName();
compName = compName.toLowerCase();
if (compName.equals(name)) {
return pet;
}
}
}
return null;
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -10,11 +10,16 @@
@Setter
@NoArgsConstructor
@AllArgsConstructor
@Builder
@Entity
@Table(name = "types")
public class PetType extends BaseEntity {

@Builder
public PetType(Long id, String name) {
super(id);
this.name = name;
}

@Column(name = "name")
private String name;

Expand Down
Original file line number Diff line number Diff line change
@@ -1,17 +1,19 @@
package spring.framework.petclinic.controllers;

import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.util.StringUtils;
import org.springframework.validation.BindingResult;
import org.springframework.web.bind.WebDataBinder;
import org.springframework.web.bind.annotation.InitBinder;
import org.springframework.web.bind.annotation.ModelAttribute;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.*;
import spring.framework.petclinic.model.Owner;
import spring.framework.petclinic.model.Pet;
import spring.framework.petclinic.model.PetType;
import spring.framework.petclinic.services.OwnerService;
import spring.framework.petclinic.services.PetService;
import spring.framework.petclinic.services.PetTypeService;

import javax.validation.Valid;
import java.util.Collection;

@Controller
Expand Down Expand Up @@ -44,4 +46,47 @@ public Owner findOwner(@PathVariable("ownerId") Long ownerId) {
public void initOwnerBinder(WebDataBinder dataBinder) {
dataBinder.setDisallowedFields("id");
}

@GetMapping("/pets/new")
public String initCreationForm(Owner owner, Model model) {
Pet pet = new Pet();
owner.getPets().add(pet);
pet.setOwner(owner);
model.addAttribute("pet", pet);
return VIEWS_PETS_CREATE_OR_UPDATE_FORM;
}

@PostMapping("/pets/new")
public String processCreationForm(Owner owner, @Valid Pet pet, BindingResult result, Model model) {
if (StringUtils.hasLength(pet.getName()) && pet.isNew() && owner.getPet(pet.getName(), true) != null) {
result.rejectValue("name", "duplicate", "already exists");
}
owner.getPets().add(pet);
if (result.hasErrors()) {
model.addAttribute("pet", pet);
return VIEWS_PETS_CREATE_OR_UPDATE_FORM;
} else {
petService.save(pet);
return "redirect:/owners/" + owner.getId();
}
}

@GetMapping("/pets/{petId}/edit")
public String initUpdateForm(@PathVariable("petId") Long petId, Model model) {
model.addAttribute("pet", petService.findById(petId));
return VIEWS_PETS_CREATE_OR_UPDATE_FORM;
}

@PostMapping("/pets/{petId}/edit")
public String processUpdateForm(@Valid Pet pet, BindingResult result, Owner owner, Model model) {
if (result.hasErrors()) {
pet.setOwner(owner);
model.addAttribute("pet", pet);
return VIEWS_PETS_CREATE_OR_UPDATE_FORM;
} else {
owner.getPets().add(pet);
petService.save(pet);
return "redirect:/owners/" + owner.getId();
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
package spring.framework.petclinic.formatters;

import org.springframework.format.Formatter;
import org.springframework.stereotype.Component;
import spring.framework.petclinic.model.PetType;
import spring.framework.petclinic.services.PetTypeService;

import java.text.ParseException;
import java.util.Collection;
import java.util.Locale;

@Component
public class PetTypeFormatter implements Formatter<PetType> {

PetTypeService petTypeService;

public PetTypeFormatter(PetTypeService petTypeService) {
this.petTypeService = petTypeService;
}

@Override
public String print(PetType petType, Locale locale) {
return petType.getName();
}

@Override
public PetType parse(String text, Locale locale) throws ParseException {
Collection<PetType> findPetTypes = petTypeService.findAll();
for (PetType type : findPetTypes) {
if (type.getName().equals(text)) {
return type;
}
}
throw new ParseException("type not found: " + text, 0);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
<html xmlns:th="https://www.thymeleaf.org"
th:replace="~{fragments/layout :: layout (~{::body},'owners')}">

<body>

<h2>
<th:block th:if="${pet['new']}">New</th:block>
Pet
</h2>
<form th:object="${pet}" class="form-horizontal" method="post">
<input type="hidden" name="id" th:value="*{id}"/>
<div class="form-group has-feedback">
<div class="form-group">
<label class="col-sm-2 control-label">Owner</label>
<div class="col-sm-10">
<span th:text="${pet.owner?.firstName + ' ' + pet.owner?.lastName}"/>
</div>
</div>
<input
th:replace="~{fragments/inputField :: input ('Name', 'name', 'text')}"/>
<input
th:replace="~{fragments/inputField :: input ('Birth Date', 'birthDate', 'date')}"/>
<input
th:replace="~{fragments/selectField :: select ('Type', 'petType', ${types})}"/>
</div>
<div class="form-group">
<div class="col-sm-offset-2 col-sm-10">
<button
th:with="text=${pet['new']} ? 'Add Pet' : 'Update Pet'"
class="btn btn-default" type="submit" th:text="${text}">Add
Pet
</button>
</div>
</div>
</form>

</body>

</html>
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
<html xmlns:th="https://www.thymeleaf.org"
th:replace="~{fragments/layout :: layout (~{::body},'owners')}">

<body>

<h2>
<th:block th:if="${visit['new']}">New</th:block>
Visit
</h2>

<b>Pet</b>
<table class="table table-striped">
<thead>
<tr>
<th>Name</th>
<th>Birth Date</th>
<th>Type</th>
<th>Owner</th>
</tr>
</thead>
<tr>
<td th:text="${pet.name}"></td>
<td
th:text="${#temporals.format(pet.birthDate, 'yyyy-MM-dd')}"></td>
<td th:text="${pet.type}"></td>
<td
th:text="${pet.owner?.firstName + ' ' + pet.owner?.lastName}"></td>
</tr>
</table>

<form th:object="${visit}" class="form-horizontal" method="post">
<div class="form-group has-feedback">
<input
th:replace="~{fragments/inputField :: input ('Date', 'date', 'date')}"/>
<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-default" type="submit">Add Visit</button>
</div>
</div>
</form>

<br/>
<b>Previous Visits</b>
<table class="table table-striped">
<tr>
<th>Date</th>
<th>Description</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>
</table>

</body>
</html>
Original file line number Diff line number Diff line change
@@ -0,0 +1,112 @@
package spring.framework.petclinic.controllers;

import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.mockito.InjectMocks;
import org.mockito.Mock;
import org.mockito.junit.jupiter.MockitoExtension;
import org.springframework.test.web.servlet.MockMvc;
import org.springframework.test.web.servlet.setup.MockMvcBuilders;
import spring.framework.petclinic.model.Owner;
import spring.framework.petclinic.model.Pet;
import spring.framework.petclinic.model.PetType;
import spring.framework.petclinic.services.OwnerService;
import spring.framework.petclinic.services.PetService;
import spring.framework.petclinic.services.PetTypeService;

import java.util.HashSet;
import java.util.Set;

import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyLong;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get;
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.*;

@ExtendWith(MockitoExtension.class)
class PetTypeTest {

@Mock
PetService petService;

@Mock
OwnerService ownerService;

@Mock
PetTypeService petTypeService;

@InjectMocks
PetController petController;

MockMvc mockMvc;
Owner owner;
Set<PetType> petTypes;


@BeforeEach
void setUp() {
owner = Owner.builder().id(1L).build();

petTypes = new HashSet<>();
petTypes.add(PetType.builder().id(1L).name("Dog").build());
petTypes.add(PetType.builder().id(2L).name("Cat").build());

mockMvc = MockMvcBuilders.standaloneSetup(petController).build();
}

@Test
void initCreationForm() throws Exception {
when(ownerService.findById(anyLong())).thenReturn(owner);
when(petTypeService.findAll()).thenReturn(petTypes);

mockMvc.perform(get("/owners/1/pets/new"))
.andExpect(status().isOk())
.andExpect(model().attributeExists("owner"))
.andExpect(model().attributeExists("pet"))
.andExpect(view().name("pets/createOrUpdatePetForm"));
}

@Test
void processCreationForm() throws Exception {
when(ownerService.findById(anyLong())).thenReturn(owner);
when(petTypeService.findAll()).thenReturn(petTypes);

mockMvc.perform(post("/owners/1/pets/new"))
.andExpect(status().is3xxRedirection())
.andExpect(view().name("redirect:/owners/1"));

verify(petService).save(any());
}

@Test
void initUpdateForm() throws Exception {
Pet pet = new Pet();
pet.setId(2L);

when(ownerService.findById(anyLong())).thenReturn(owner);
when(petTypeService.findAll()).thenReturn(petTypes);
when(petService.findById(anyLong())).thenReturn(pet);

mockMvc.perform(get("/owners/1/pets/2/edit"))
.andExpect(status().isOk())
.andExpect(model().attributeExists("owner"))
.andExpect(model().attributeExists("pet"))
.andExpect(view().name("pets/createOrUpdatePetForm"));
}

@Test
void processUpdateForm() throws Exception {
when(ownerService.findById(anyLong())).thenReturn(owner);
when(petTypeService.findAll()).thenReturn(petTypes);

mockMvc.perform(post("/owners/1/pets/2/edit"))
.andExpect(status().is3xxRedirection())
.andExpect(view().name("redirect:/owners/1"));

verify(petService).save(any());
}

}

0 comments on commit 079f440

Please sign in to comment.