diff --git a/src/main/java/com/example/AKTours/model/entity/City.java b/src/main/java/com/example/AKTours/model/entity/City.java index 17c0bfc..a5c8d01 100644 --- a/src/main/java/com/example/AKTours/model/entity/City.java +++ b/src/main/java/com/example/AKTours/model/entity/City.java @@ -1,24 +1,28 @@ package com.example.AKTours.model.entity; +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; import lombok.AllArgsConstructor; +import lombok.Builder; import lombok.Data; import lombok.NoArgsConstructor; import javax.persistence.*; import java.util.Set; -@Entity -@Table(name = "Cities") -@Data @AllArgsConstructor +@Builder +@Data +@Entity +@JsonIgnoreProperties({"hotels", "airports"}) @NoArgsConstructor +@Table(name = "Cities") public class City { @Id @GeneratedValue(strategy = GenerationType.AUTO) private Long id; - @Column(name="city_name") + @Column(name = "city_name") private String name; @OneToMany(cascade = CascadeType.ALL) @@ -29,5 +33,13 @@ public class City { @JoinColumn(name = "city_id") private Set airports; + @ManyToOne(fetch = FetchType.EAGER) + @JoinColumn(name = "country_id") + private Country country; + + public City(String name, Country country) { + this.name = name; + this.country = country; + } } diff --git a/src/main/java/com/example/AKTours/repository/CityRepository.java b/src/main/java/com/example/AKTours/repository/CityRepository.java index 03ac901..8175364 100644 --- a/src/main/java/com/example/AKTours/repository/CityRepository.java +++ b/src/main/java/com/example/AKTours/repository/CityRepository.java @@ -1,10 +1,18 @@ package com.example.AKTours.repository; - import com.example.AKTours.model.entity.City; +import java.util.List; +import org.springframework.data.jpa.repository.Query; import org.springframework.data.repository.CrudRepository; +import org.springframework.stereotype.Repository; +@Repository public interface CityRepository extends CrudRepository { - City findCityByName(String name); + public City findCityByName(String name); + + public List findCitiesByCountryName(String name); + + @Query(value = "SELECT *FROM cities c JOIN countries count ON c.country_id = count.id JOIN continents cont ON count.continent_id = cont.continent_id WHERE cont.continent_name=?1", nativeQuery = true) + public List findCitiesByContinentName(String name); } diff --git a/src/main/java/com/example/AKTours/web/controllers/CityController.java b/src/main/java/com/example/AKTours/web/controllers/CityController.java index 676455c..1a86548 100644 --- a/src/main/java/com/example/AKTours/web/controllers/CityController.java +++ b/src/main/java/com/example/AKTours/web/controllers/CityController.java @@ -1,47 +1,74 @@ package com.example.AKTours.web.controllers; import com.example.AKTours.model.entity.City; +import com.example.AKTours.web.exceptions.EntityNotFoundException; import com.example.AKTours.web.service.CityService; -import io.swagger.annotations.ApiOperation; -import io.swagger.annotations.ApiParam; -import io.swagger.annotations.ApiResponse; -import io.swagger.annotations.ApiResponses; +import io.swagger.annotations.*; + +import java.util.List; + import lombok.extern.log4j.Log4j2; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.http.HttpStatus; +import org.springframework.http.ResponseEntity; import org.springframework.stereotype.Controller; -import org.springframework.ui.Model; +import org.springframework.web.bind.annotation.CrossOrigin; import org.springframework.web.bind.annotation.PathVariable; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestMethod; -import java.util.List; - -@Log4j2 +@Api(value = "City Management System") @Controller -@RequestMapping(value = {"/", "/cities"}) +@CrossOrigin(origins = "http://localhost:4200") +@Log4j2 +@RequestMapping(value = {"/cities"}) public class CityController { private final CityService cityService; + @Autowired public CityController(CityService cityService) { this.cityService = cityService; } @ApiOperation(value = "Shows all cities", response = List.class) + @ApiResponses(value = { + @ApiResponse(code = 200, message = "Successfully found cities")}) @RequestMapping(method = RequestMethod.GET) - public String cities(Model model) { - model.addAttribute("cities", cityService.findAll()); - return "cities"; + public ResponseEntity allCities() { + return new ResponseEntity<>(cityService.findAll(), HttpStatus.OK); } @ApiOperation(value = "Displays cities by name", response = City.class) @ApiResponses(value = { @ApiResponse(code = 200, message = "Successfully found cities")}) @RequestMapping(value = "/name/{name}", method = RequestMethod.GET) - public String findByCityName(Model model, - @ApiParam(value = "Name of the city", required = true) - @PathVariable("name") String name) throws Exception { + public ResponseEntity findByCityName( + @ApiParam(value = "Name of the city", required = true) + @PathVariable("name") String name) throws Exception { log.info("Invoke findByCityName method"); - Model cityName = model.addAttribute("cityName", cityService.findCityByName(name)); - return "cityName"; + return new ResponseEntity<>(cityService.findCityByName(name), HttpStatus.OK); + } + + @ApiOperation(value = "Displays cities by continent name", response = City.class) + @ApiResponses(value = { + @ApiResponse(code = 200, message = "Successfully found cities")}) + @RequestMapping(value = "/byContinentName/{name}", method = RequestMethod.GET) + public ResponseEntity findCitiesByContinentName( + @ApiParam(value = "Name of the continent", required = true) + @PathVariable("name") String name) throws EntityNotFoundException { + log.info("Invoke findCitiesByContinentName method"); + return new ResponseEntity<>(cityService.findCityByContinentName(name), HttpStatus.OK); + } + + @ApiOperation(value = "Displays cities by country name", response = City.class) + @ApiResponses(value = { + @ApiResponse(code = 200, message = "Successfully found cities")}) + @RequestMapping(value = "/byCountryName/{name}", method = RequestMethod.GET) + public ResponseEntity findCitiesByCountryName( + @ApiParam(value = "Name of the continent", required = true) + @PathVariable("name") String name) throws EntityNotFoundException { + log.info("Invoke findCitiesByCountryName method"); + return new ResponseEntity<>(cityService.findCityByCountryName(name), HttpStatus.OK); } } diff --git a/src/main/java/com/example/AKTours/web/controllers/TripController.java b/src/main/java/com/example/AKTours/web/controllers/TripController.java index 9a5c865..83c6b7b 100644 --- a/src/main/java/com/example/AKTours/web/controllers/TripController.java +++ b/src/main/java/com/example/AKTours/web/controllers/TripController.java @@ -22,7 +22,6 @@ @RestController @Api(value = "Trips Management System") @CrossOrigin(origins = "http://localhost:4200") - public class TripController { private final TripService tripService; @@ -45,12 +44,13 @@ public ResponseEntity findAllTrips() throws EntityNotFoundException { @ApiResponse(code = 200, message = "Successfully found trips")}) @RequestMapping(value = "/tripsByHotel/{name}", method = RequestMethod.GET) public ResponseEntity findTripsByHotelName( - @ApiParam(value = "Name of the hotel", required = true) - @PathVariable("name") String name) throws EntityNotFoundException { + @ApiParam(value = "Name of the hotel", required = true) + @PathVariable("name") String name) throws EntityNotFoundException { log.info("Invoke findTripsByHotelName method"); return new ResponseEntity<>(tripService.findTripByHotelName(name), HttpStatus.OK); } + @ApiOperation(value = "Displays trips by city name", response = Trip.class) @ApiResponses(value = { @ApiResponse(code = 200, message = "Successfully found trips")}) @@ -59,8 +59,13 @@ public ResponseEntity findTripsByCityName( @ApiParam(value = "Name of the city", required = true) @PathVariable("name") String name) throws EntityNotFoundException { log.info("Invoke findTripsByCityName method"); - return new ResponseEntity<>(tripService.findTripByCityName(name), HttpStatus.OK); + if (name.equals("Select")) { + return new ResponseEntity<>(tripService.findAllTrips(), HttpStatus.OK); + } else { + return new ResponseEntity<>(tripService.findTripByCityName(name), HttpStatus.OK); + } } + @ApiOperation(value = "Displays trips by country name", response = Trip.class) @ApiResponses(value = { @ApiResponse(code = 200, message = "Successfully found trips")}) @@ -69,11 +74,12 @@ public ResponseEntity findTripsByCountryName( @ApiParam(value = "Name of the country", required = true) @PathVariable("name") String name) throws EntityNotFoundException { log.info("Invoke findTripsByCountryName method"); - if(name.equals("Select")){ - return new ResponseEntity<>(tripService.findAllTrips(),HttpStatus.OK); - }else{ - return new ResponseEntity<>(tripService.findTripByCountryName(name), HttpStatus.OK); - }} + if (name.equals("Select")) { + return new ResponseEntity<>(tripService.findAllTrips(), HttpStatus.OK); + } else { + return new ResponseEntity<>(tripService.findTripByCountryName(name), HttpStatus.OK); + } + } @ApiOperation(value = "Displays trips by continent name", response = Trip.class) @ApiResponses(value = { @@ -90,17 +96,17 @@ public ResponseEntity findTripsByContinentName( } } - @ApiOperation(value = "Displays trips by date", response = Trip.class) - @ApiResponses(value = { - @ApiResponse(code = 200, message = "Successfully found trips")}) - @RequestMapping(value = "/tripsByDate/{date}", method = RequestMethod.GET) - public ResponseEntity findTripsByContinentName ( - @DateTimeFormat(iso = DateTimeFormat.ISO.DATE) - @ApiParam(value = "Date of the trip", required = true) - @PathVariable("date") LocalDate date) throws EntityNotFoundException { - log.info("Invoke findTripsByContinentName method"); - return new ResponseEntity<>(tripService.findTripByDate(date), HttpStatus.OK); - } + @ApiOperation(value = "Displays trips by date", response = Trip.class) + @ApiResponses(value = { + @ApiResponse(code = 200, message = "Successfully found trips")}) + @RequestMapping(value = "/tripsByDate/{date}", method = RequestMethod.GET) + public ResponseEntity findTripsByContinentName( + @DateTimeFormat(iso = DateTimeFormat.ISO.DATE) + @ApiParam(value = "Date of the trip", required = true) + @PathVariable("date") LocalDate date) throws EntityNotFoundException { + log.info("Invoke findTripsByContinentName method"); + return new ResponseEntity<>(tripService.findTripByDate(date), HttpStatus.OK); + } @ApiOperation(value = "Displays trips by price", response = Trip.class) @@ -109,9 +115,9 @@ public ResponseEntity findTripsByContinentName ( @RequestMapping(value = "/tripsByPrice/{price}", method = RequestMethod.GET) public ResponseEntity findTripsByContinentName( @ApiParam(value = "Price of the trip", required = true) - @PathVariable("price")BigDecimal price) throws EntityNotFoundException { + @PathVariable("price") BigDecimal price) throws EntityNotFoundException { log.info("Invoke findTripsByContinentName method"); return new ResponseEntity<>(tripService.findTripByPrice(price), HttpStatus.OK); } - } +} diff --git a/src/main/java/com/example/AKTours/web/service/CityService.java b/src/main/java/com/example/AKTours/web/service/CityService.java index 482da06..558464b 100644 --- a/src/main/java/com/example/AKTours/web/service/CityService.java +++ b/src/main/java/com/example/AKTours/web/service/CityService.java @@ -2,17 +2,19 @@ import com.example.AKTours.model.entity.City; import com.example.AKTours.repository.CityRepository; -import lombok.extern.log4j.Log4j2; -import org.springframework.stereotype.Service; - +import com.example.AKTours.web.exceptions.EntityNotFoundException; import java.util.List; import java.util.stream.Collectors; import java.util.stream.StreamSupport; +import lombok.extern.log4j.Log4j2; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; @Log4j2 @Service public class CityService { + @Autowired private final CityRepository cityRepository; public CityService(CityRepository cityRepository) { @@ -20,15 +22,32 @@ public CityService(CityRepository cityRepository) { } public List findAll() { - log.info("Invoke city repisitory findAll "); + log.info("Invoke CityRepisitory findAll "); List collect = StreamSupport.stream(cityRepository.findAll().spliterator(), false) .collect(Collectors.toList()); return collect; - } public City findCityByName(String name) { - log.info("Invoke city repository using" + name); + log.info("Invoke CityRepository findCityByName using " + name); return cityRepository.findCityByName(name); } + + public List findCityByCountryName(String name) throws EntityNotFoundException { + log.info("Invoke CityRepository findCityByCoutryName using " + name); + if (!cityRepository.findCitiesByCountryName(name).isEmpty()) { + return cityRepository.findCitiesByCountryName(name); + } else { + throw new EntityNotFoundException("Not found any cities for country " + name); + } + } + + public List findCityByContinentName(String name) throws EntityNotFoundException { + log.info("Invoke CityRepository findCityByContinentName using " + name); + if (!cityRepository.findCitiesByContinentName(name).isEmpty()) { + return cityRepository.findCitiesByContinentName(name); + } else { + throw new EntityNotFoundException("Not found any cities for continent " + name); + } + } } diff --git a/src/main/java/com/example/AKTours/web/service/CountryService.java b/src/main/java/com/example/AKTours/web/service/CountryService.java index 222d095..273d17f 100644 --- a/src/main/java/com/example/AKTours/web/service/CountryService.java +++ b/src/main/java/com/example/AKTours/web/service/CountryService.java @@ -1,20 +1,17 @@ package com.example.AKTours.web.service; import com.example.AKTours.model.entity.Country; -import com.example.AKTours.model.entity.Hotel; import com.example.AKTours.repository.CountryRepository; -import lombok.extern.log4j.Log4j2; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.stereotype.Service; - import java.util.List; import java.util.stream.Collectors; import java.util.stream.StreamSupport; +import lombok.extern.log4j.Log4j2; +import org.springframework.stereotype.Service; + @Log4j2 @Service public class CountryService { - // @Autowired private final CountryRepository countryRepository; public CountryService(CountryRepository countryRepository) { @@ -30,10 +27,10 @@ public List findAll() { public Country findByCountryName(String name) { log.info("Invoke CountryRepository findByCountryName using " + name); - return countryRepository.findCountryByName(name); } - public List findCountryByContinentName(String name){ + + public List findCountryByContinentName(String name) { log.info("Invoke CountryRepository findCountryByContinent_name using " + name); return StreamSupport .stream(countryRepository.findCountryByContinent_Name(name).spliterator(), false) diff --git a/src/test/java/com/example/AKTours/web/controllers/CityControllerTest.java b/src/test/java/com/example/AKTours/web/controllers/CityControllerTest.java new file mode 100644 index 0000000..9a15533 --- /dev/null +++ b/src/test/java/com/example/AKTours/web/controllers/CityControllerTest.java @@ -0,0 +1,89 @@ +package com.example.AKTours.web.controllers; + +import com.example.AKTours.model.entity.City; +import com.example.AKTours.model.entity.Continent; +import com.example.AKTours.model.entity.Country; +import com.example.AKTours.web.service.CityService; + +import java.util.ArrayList; +import java.util.List; + +import org.hamcrest.core.StringContains; +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.Mockito; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.autoconfigure.web.servlet.WebMvcTest; +import org.springframework.boot.test.mock.mockito.MockBean; +import org.springframework.http.MediaType; +import org.springframework.test.context.junit4.SpringRunner; +import org.springframework.test.web.servlet.MockMvc; + +import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.*; + +@WebMvcTest(CityController.class) +@RunWith(SpringRunner.class) +public class CityControllerTest { + private City cityOne; + private City cityTwo; + List cities; + private Continent continent; + private Country countryOne; + private Country countryTwo; + + @Autowired + MockMvc mockMvc; + + @MockBean + private CityService cityService; + + @Before + public void setUp() { + continent = new Continent("South America"); + countryOne = new Country("Panama", continent); + countryTwo = new Country("Brazil", continent); + cityOne = new City("Panama", countryOne); + cityTwo = new City("Rio De Jeneiro", countryTwo); + cities = new ArrayList<>(); + cities.add(cityOne); + cities.add(cityTwo); + } + + @Test + public void cities() throws Exception { + Mockito.when(cityService.findAll()).thenReturn(cities); + mockMvc.perform(get("/cities")) + .andExpect(status().isOk()) + .andExpect(content().contentType(MediaType.APPLICATION_JSON_UTF8)) + .andExpect(jsonPath("$[0].name", new StringContains("Panama"))); + } + + @Test + public void findByCityName() throws Exception { + Mockito.when(cityService.findCityByName(Mockito.anyString())).thenReturn(cityOne); + mockMvc.perform(get("/cities/name/Panama")) + .andExpect(status().isOk()) + .andExpect(content().contentType(MediaType.APPLICATION_JSON_UTF8)) + .andExpect(jsonPath("name", new StringContains("Panama"))); + } + + @Test + public void findCitiesByContinentName() throws Exception { + Mockito.when(cityService.findCityByContinentName(Mockito.anyString())).thenReturn(cities); + mockMvc.perform(get("/cities/byContinentName/South America")) + .andExpect(status().isOk()) + .andExpect(content().contentType(MediaType.APPLICATION_JSON_UTF8)) + .andExpect(jsonPath("$[0].name", new StringContains("Panama"))); + } + + @Test + public void findCitiesByCountryName() throws Exception { + Mockito.when(cityService.findCityByCountryName(Mockito.anyString())).thenReturn(cities); + mockMvc.perform(get("/cities/byCountryName/Panama")) + .andExpect(status().isOk()) + .andExpect(content().contentType(MediaType.APPLICATION_JSON_UTF8)) + .andExpect(jsonPath("$[0].name", new StringContains("Panama"))); + } +} \ No newline at end of file diff --git a/src/test/java/com/example/AKTours/web/controllers/TripControllerTest.java b/src/test/java/com/example/AKTours/web/controllers/TripControllerTest.java index 6550c77..0084c81 100644 --- a/src/test/java/com/example/AKTours/web/controllers/TripControllerTest.java +++ b/src/test/java/com/example/AKTours/web/controllers/TripControllerTest.java @@ -19,6 +19,7 @@ import java.time.LocalDate; import java.util.ArrayList; import java.util.List; + ; import static java.time.format.DateTimeFormatter.ofPattern; import static org.assertj.core.internal.bytebuddy.matcher.ElementMatchers.is; @@ -33,6 +34,7 @@ public class TripControllerTest { @Autowired private MockMvc mockMvc; + @MockBean private TripService tripService; diff --git a/src/test/java/com/example/AKTours/web/service/CityServiceTest.java b/src/test/java/com/example/AKTours/web/service/CityServiceTest.java new file mode 100644 index 0000000..a280954 --- /dev/null +++ b/src/test/java/com/example/AKTours/web/service/CityServiceTest.java @@ -0,0 +1,79 @@ +package com.example.AKTours.web.service; + +import com.example.AKTours.model.entity.City; +import com.example.AKTours.model.entity.Continent; +import com.example.AKTours.model.entity.Country; +import com.example.AKTours.repository.CityRepository; +import com.example.AKTours.web.exceptions.EntityNotFoundException; + +import java.util.ArrayList; +import java.util.List; +import java.util.Optional; + +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.Mockito; +import org.springframework.boot.test.mock.mockito.MockBean; +import org.springframework.test.context.junit4.SpringRunner; + +import static org.assertj.core.api.Assertions.assertThat; + +@RunWith(SpringRunner.class) +public class CityServiceTest { + + private CityService cityService; + private City cityOne; + private City cityTwo; + List cities; + private Continent continent; + private Country countryOne; + private Country countryTwo; + + @MockBean + private CityRepository cityRepository; + + @Before + public void setUp() throws Exception { + cityService = new CityService(cityRepository); + continent = new Continent("South America"); + countryOne = new Country("Panama", continent); + countryTwo = new Country("Brazil", continent); + cityOne = new City("Panama", countryOne); + cityTwo = new City("Rio De Janeiro", countryTwo); + cities = new ArrayList<>(); + cities.add(cityOne); + cities.add(cityTwo); + } + + @Test + public void findAll() { + Mockito.when(cityRepository.findAll()).thenReturn(cities); + List resultListOfCities = cityService.findAll(); + assertThat(resultListOfCities.contains(cityOne)); + assertThat(resultListOfCities.contains(cityTwo)); + assertThat(resultListOfCities.size()).isEqualTo(2); + } + + @Test + public void findCityByName() throws EntityNotFoundException { + Mockito.when(cityRepository.findCityByName(Mockito.anyString())).thenReturn(cityOne); + City resultCity = cityService.findCityByName("SomeName"); + assertThat(resultCity.getName()).isEqualTo("Panama"); + } + + @Test + public void findCityByContinentName() throws EntityNotFoundException { + Mockito.when(cityRepository.findCitiesByContinentName(Mockito.anyString())).thenReturn(cities); + List resultCity = cityService.findCityByContinentName("Something"); + assertThat(resultCity.get(0).getName()).isEqualTo("Panama"); + assertThat(resultCity.size()).isEqualTo(2); + } + @Test + public void findCityByCountryName() throws EntityNotFoundException { + Mockito.when(cityRepository.findCitiesByCountryName(Mockito.anyString())).thenReturn(cities); + List resultCity = cityService.findCityByCountryName("Something"); + assertThat(resultCity.get(0).getName()).isEqualTo("Panama"); + assertThat(resultCity.size()).isEqualTo(2); + } +} \ No newline at end of file