Commit 1bc8e57e authored by Matija Obreza's avatar Matija Obreza

Merge branch 'genesys-ui-92-geo-module' into 'master'

API endpoints for Geo module

See merge request genesys-pgr/genesys-server!266
parents aba6dd32 3a45bce9
/*
* Copyright 2018 Global Crop Diversity Trust
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.genesys2.server.api.v1;
import java.util.List;
import com.fasterxml.jackson.annotation.JsonView;
import io.swagger.annotations.Api;
import org.genesys.blocks.model.JsonViews;
import org.genesys2.server.api.ApiBaseController;
import org.genesys2.server.model.impl.Country;
import org.genesys2.server.model.impl.GeoRegion;
import org.genesys2.server.service.GeoRegionService;
import org.genesys2.server.service.GeoService;
import org.genesys2.spring.ResourceNotFoundException;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.i18n.LocaleContextHolder;
import org.springframework.http.MediaType;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RestController;
@RestController("geoApi1")
@RequestMapping(value = { org.genesys2.server.api.v1.GeoController.CONTROLLER_URL })
@Api(tags = { "geo" })
public class GeoController extends ApiBaseController {
public static final String CONTROLLER_URL = ApiBaseController.APIv1_BASE + "/geo";
@Autowired
private GeoService geoService;
@Autowired
private GeoRegionService geoRegionService;
@RequestMapping(value = "/countries", method = RequestMethod.GET, produces = { MediaType.APPLICATION_JSON_VALUE })
public List<Country> listCountries() {
LOG.info("Listing countries");
return geoService.listActive(LocaleContextHolder.getLocale());
}
@JsonView(JsonViews.Public.class)
@RequestMapping(value = "/country/details/{iso3code}", method = RequestMethod.GET, produces = { MediaType.APPLICATION_JSON_VALUE })
public GeoService.CountryDetails getCountryDetails(@PathVariable("iso3code") String iso3code) {
LOG.info("Getting country details bu ISO3 code {}", iso3code);
return geoService.getDetails(iso3code);
}
@RequestMapping(value = "/country/{iso3code}", method = RequestMethod.GET, produces = { MediaType.APPLICATION_JSON_VALUE })
public Country getCountry(@PathVariable("iso3code") String iso3code) {
LOG.info("Getting country {}", iso3code);
Country country = geoService.getCountry(iso3code);
if (country == null) {
throw new ResourceNotFoundException();
}
return country;
}
@RequestMapping(value = "/regions", method = RequestMethod.GET, produces = { MediaType.APPLICATION_JSON_VALUE })
public List<GeoRegion> getGeoRegions() {
LOG.info("Listing regions");
return geoRegionService.findAll();
}
@RequestMapping(value = "/region/details/{isoCode}", method = RequestMethod.GET, produces = { MediaType.APPLICATION_JSON_VALUE })
public GeoRegionService.RegionDetails getGeoRegionDetails(@PathVariable("isoCode") String isoCode) {
LOG.info("Getting region {}", isoCode);
return geoRegionService.getDetails(isoCode);
}
}
\ No newline at end of file
......@@ -3,6 +3,7 @@ package org.genesys2.server.mvc;
import java.util.List;
import java.util.stream.Collectors;
import org.genesys2.server.exception.NotFoundElement;
import org.genesys2.server.model.impl.Country;
import org.genesys2.server.model.impl.GeoRegion;
import org.genesys2.server.persistence.CountryRepository;
......@@ -38,15 +39,10 @@ public class GeoRegionController extends BaseController {
}
@RequestMapping("/{isoCode}")
public String view(ModelMap model, @PathVariable(value = "isoCode") String code) {
public String view(ModelMap model, @PathVariable(value = "isoCode") String code) throws NotFoundElement {
GeoRegion geoRegion = geoRegionService.find(code);
if (geoRegion == null) {
LOG.error("Can't find region for region code {}", code);
throw new ResourceNotFoundException("Can't find region for region code " + code);
}
List<Country> countryList = geoRegion.getCountries().stream().filter(country -> isCurrent(country)).collect(Collectors.toList());
Country.sort(countryList, getLocale());
......
package org.genesys2.server.service;
import org.genesys2.server.model.impl.Country;
import org.genesys2.server.model.impl.GeoRegion;
import org.xml.sax.SAXException;
import javax.xml.parsers.ParserConfigurationException;
import java.io.IOException;
import java.io.Serializable;
import java.util.Collection;
import java.util.List;
import java.util.Locale;
import java.util.Set;
import com.fasterxml.jackson.annotation.JsonUnwrapped;
import org.genesys2.server.model.impl.Country;
import org.genesys2.server.model.impl.GeoRegion;
import org.xml.sax.SAXException;
public interface GeoRegionService {
GeoRegion find(String regionIsoCode);
......@@ -41,4 +43,21 @@ public interface GeoRegionService {
*/
Collection<String> countryCodesFor(Set<String> regionCodes);
RegionDetails getDetails(String isoCode);
public static class RegionDetails implements Serializable {
private static final long serialVersionUID = -8652090344263391432L;
@JsonUnwrapped
public GeoRegion region;
public List<GeoRegion> subRegions;
public static RegionDetails from(GeoRegion region, List<GeoRegion> subRegions) {
RegionDetails regionDetails = new RegionDetails();
regionDetails.region = region;
regionDetails.subRegions = subRegions;
return regionDetails;
}
}
}
/**
* Copyright 2014 Global Crop Diversity Trust
/*
* Copyright 2018 Global Crop Diversity Trust
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
......@@ -12,14 +12,19 @@
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
**/
*/
package org.genesys2.server.service;
import java.io.IOException;
import java.io.Serializable;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import com.fasterxml.jackson.annotation.JsonUnwrapped;
import com.fasterxml.jackson.annotation.JsonView;
import org.genesys.blocks.model.JsonViews;
import org.genesys2.server.model.impl.Country;
import org.genesys2.server.model.impl.FaoInstitute;
import org.genesys2.server.model.impl.ITPGRFAStatus;
......@@ -129,4 +134,33 @@ public interface GeoService {
*/
String getBoundingBox(AppliedFilters filters);
CountryDetails getDetails(String iso3code);
public static class CountryDetails implements Serializable {
private static final long serialVersionUID = -1556370638451781192L;
@JsonUnwrapped
public Country country;
@JsonView({ JsonViews.Public.class })
public List<FaoInstitute> faoInstitutes;
public List<FaoInstitute> genesysInstitutes;
@JsonView({ JsonViews.Public.class })
public Map<String, ElasticsearchService.TermResult> overview;
public Long accessionCount;
public Long countByLocation;
public static CountryDetails from(Country country, Long accessionCount, Long countByLocation, List<FaoInstitute> faoInstitutes, List<FaoInstitute> genesysInstitutes, Map<String, ElasticsearchService.TermResult> overview) {
CountryDetails countryDetails = new CountryDetails();
countryDetails.country = country;
countryDetails.accessionCount = accessionCount;
countryDetails.countByLocation = countByLocation;
countryDetails.faoInstitutes = faoInstitutes;
countryDetails.genesysInstitutes = genesysInstitutes;
countryDetails.overview = overview;
return countryDetails;
}
}
}
......@@ -28,6 +28,7 @@ import java.util.stream.Collectors;
import javax.xml.parsers.ParserConfigurationException;
import org.genesys2.server.exception.NotFoundElement;
import org.genesys2.server.model.impl.Country;
import org.genesys2.server.model.impl.GeoRegion;
import org.genesys2.server.model.impl.QGeoRegion;
......@@ -78,6 +79,9 @@ public class GeoRegionServiceImpl implements GeoRegionService {
@Override
public GeoRegion find(String regionIsoCode) {
GeoRegion geoRegion = geoRegionRepository.findByIsoCode(regionIsoCode);
if (geoRegion == null) {
throw new NotFoundElement("Can't find region for region code " + regionIsoCode);
}
geoRegion.getCountries().size();
return geoRegion;
}
......@@ -238,6 +242,14 @@ public class GeoRegionServiceImpl implements GeoRegionService {
return x.fetch();
}
@Override
public RegionDetails getDetails(final String isoCode) {
GeoRegion region = find(isoCode);
region.setCountries(region.getCountries().stream().filter(Country::isCurrent).collect(Collectors.toList()));
List<GeoRegion> subRegions = getChildren(region.getIsoCode());
return RegionDetails.from(region, subRegions);
}
/* (non-Javadoc)
* @see org.genesys2.server.service.GeoRegionService#conversionToSubRegionsList(org.genesys2.server.model.impl.GeoRegion)
*/
......
/**
* Copyright 2014 Global Crop Diversity Trust
/*
* Copyright 2018 Global Crop Diversity Trust
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
......@@ -12,7 +12,7 @@
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
**/
*/
package org.genesys2.server.service.impl;
......@@ -24,20 +24,29 @@ import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.util.Set;
import java.util.TreeSet;
import java.util.stream.Collectors;
import org.apache.commons.lang3.StringUtils;
import org.genesys2.server.exception.NotFoundElement;
import org.genesys2.server.model.genesys.Accession;
import org.genesys2.server.model.impl.Country;
import org.genesys2.server.model.impl.FaoInstitute;
import org.genesys2.server.model.impl.ITPGRFAStatus;
import org.genesys2.server.persistence.CountryRepository;
import org.genesys2.server.persistence.ITPGRFAStatusRepository;
import org.genesys2.server.service.AccessionService;
import org.genesys2.server.service.CRMException;
import org.genesys2.server.service.ContentService;
import org.genesys2.server.service.ElasticsearchService;
import org.genesys2.server.service.GenesysFilterService;
import org.genesys2.server.service.GenesysService;
import org.genesys2.server.service.GeoService;
import org.genesys2.server.service.InstituteService;
import org.genesys2.server.service.filter.AccessionFilter;
import org.genesys2.server.service.filter.CountryFilter;
import org.genesys2.server.service.worker.CountryInfo;
import org.genesys2.server.service.worker.DavrosCountrySource;
import org.genesys2.server.service.worker.GeoNamesCountrySource;
......@@ -81,6 +90,18 @@ public class GeoServiceImpl implements GeoService {
@Autowired
private GenesysFilterService filterService;
@Autowired
private ElasticsearchService elasticsearchService;
@Autowired
private InstituteService instituteService;
@Autowired
private AccessionService accessionService;
@Autowired
private GenesysService genesysService;
private final ObjectMapper mapper = new ObjectMapper();
@Override
......@@ -450,6 +471,38 @@ public class GeoServiceImpl implements GeoService {
return countryRepository.autocomplete("%" + term + "%", new PageRequest(0, 10));
}
@Override
public CountryDetails getDetails(String iso3code) {
Country country = getCountry(iso3code);
if (country == null) {
throw new NotFoundElement("Cannot find country by ISO code " + iso3code);
}
AccessionFilter byCountry = new AccessionFilter();
byCountry.origin = new CountryFilter();
byCountry.origin.iso3 = new HashSet<String>(){{ add(country.getCode3()); }};
long accessionCount = accessionService.countAccessions(byCountry);
long countByLocation = genesysService.countByLocation(country);
Map<String, ElasticsearchService.TermResult> overview = getOverviewData(byCountry);
List<FaoInstitute> genesysInstitutes = instituteService.listByCountryActive(country);
List<FaoInstitute> faoInstitutes = instituteService.listByCountry(country);
return CountryDetails.from(country, accessionCount, countByLocation, faoInstitutes, genesysInstitutes, overview);
}
private Map<String, ElasticsearchService.TermResult> getOverviewData(AccessionFilter byCountryFilter) {
String[] terms = new String[] {"taxonomy.genus", "taxonomy.genusSpecies", "institute.code",
"institute.country.code3", "mlsStatus", "available"};
try {
return elasticsearchService.termStatisticsAuto(Accession.class, byCountryFilter, 10, terms);
} catch (SearchException e) {
LOG.error("Error occurred during search", e);
return null;
}
}
@Override
public String getBoundingBox(final AppliedFilters filters) {
filterService.transformFiltersIfNeed(filters);
......
/*
* Copyright 2018 Global Crop Diversity Trust
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.genesys.test.server.api.v1;
import java.util.Collections;
import static org.hamcrest.Matchers.hasSize;
import static org.hamcrest.Matchers.is;
import static org.hamcrest.Matchers.notNullValue;
import static org.springframework.restdocs.mockmvc.MockMvcRestDocumentation.document;
import static org.springframework.restdocs.mockmvc.RestDocumentationRequestBuilders.get;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.content;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.jsonPath;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
import org.genesys.test.base.AbstractApiTest;
import org.genesys2.server.api.v1.GeoController;
import org.genesys2.server.model.genesys.Accession;
import org.genesys2.server.model.genesys.AccessionId;
import org.genesys2.server.model.genesys.Taxonomy2;
import org.genesys2.server.model.impl.Country;
import org.genesys2.server.model.impl.FaoInstitute;
import org.genesys2.server.model.impl.GeoRegion;
import org.genesys2.server.persistence.AccessionRepository;
import org.genesys2.server.persistence.CountryRepository;
import org.genesys2.server.persistence.FaoInstituteRepository;
import org.genesys2.server.persistence.GeoRegionRepository;
import org.genesys2.server.service.TaxonomyService;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.MediaType;
import org.springframework.test.web.servlet.result.MockMvcResultHandlers;
import org.springframework.transaction.annotation.Transactional;
/**
* @author Maxym Borodenko
*/
@Transactional(transactionManager = "transactionManager")
public class GeoControllerTest extends AbstractApiTest {
@Autowired
private TaxonomyService taxonomyService;
@Autowired
private CountryRepository countryRepository;
@Autowired
private GeoRegionRepository geoRegionRepository;
@Autowired
private AccessionRepository accessionRepository;
@Autowired
private FaoInstituteRepository instituteRepository;
private Country country;
private GeoRegion region;
@Transactional
@Before
@Override
public void beforeTest() throws Exception {
super.beforeTest();
country = setupCountry("UKR", "Ukraine");
region = setupRegion("001", "Europe", null, null);
}
@Transactional
@After
@Override
public void cleanup() throws Exception {
geoRegionRepository.deleteAll();
accessionRepository.deleteAll();
super.cleanup();
countryRepository.deleteAll();
}
@Test
public void listCountriesTest() throws Exception {
mockMvc.perform(get(GeoController.CONTROLLER_URL.concat("/countries"))
.contentType(MediaType.APPLICATION_JSON_UTF8))
// .andDo(MockMvcResultHandlers.print())
.andExpect(status().isOk())
.andExpect(content().contentType(MediaType.APPLICATION_JSON_UTF8))
.andExpect(jsonPath("$", hasSize(1)))
.andExpect(jsonPath("$[0].id", is(country.getId().intValue())))
.andExpect(jsonPath("$[0].name", is(country.getName())))
.andExpect(jsonPath("$[0].code3", is(country.getCode3())))
.andDo(document("country-list"));
}
@Test
public void getCountryDetailsTest() throws Exception {
setupAccession();
mockMvc.perform(get(GeoController.CONTROLLER_URL.concat("/country/details/{iso3code}"), country.getCode3())
.contentType(MediaType.APPLICATION_JSON_UTF8))
// .andDo(MockMvcResultHandlers.print())
.andExpect(status().isOk())
.andExpect(content().contentType(MediaType.APPLICATION_JSON_UTF8))
.andExpect(jsonPath("$.id", is(country.getId().intValue())))
.andExpect(jsonPath("$.name", is(country.getName())))
.andExpect(jsonPath("$.code3", is(country.getCode3())))
.andExpect(jsonPath("$.overview", notNullValue()))
.andExpect(jsonPath("$.countByLocation", is(1)))
.andExpect(jsonPath("$.accessionCount", is(1)));
}
@Test
public void getGeoRegionsTest() throws Exception {
mockMvc.perform(get(GeoController.CONTROLLER_URL.concat("/regions"))
.contentType(MediaType.APPLICATION_JSON_UTF8))
// .andDo(MockMvcResultHandlers.print())
.andExpect(status().isOk())
.andExpect(content().contentType(MediaType.APPLICATION_JSON_UTF8))
.andExpect(jsonPath("$", hasSize(1)))
.andExpect(jsonPath("$[0].id", is(region.getId().intValue())))
.andExpect(jsonPath("$[0].name", is(region.getName())))
.andExpect(jsonPath("$[0].isoCode", is(region.getIsoCode())))
.andDo(document("region-list"));
}
@Test
public void getGeoRegionDetailsTest() throws Exception {
GeoRegion geoRegion = setupRegion("003", "Eastern Europe", country, region);
mockMvc.perform(get(GeoController.CONTROLLER_URL.concat("/region/details/{isoCode}"), geoRegion.getIsoCode())
.contentType(MediaType.APPLICATION_JSON_UTF8))
// .andDo(MockMvcResultHandlers.print())
.andExpect(status().isOk())
.andExpect(content().contentType(MediaType.APPLICATION_JSON_UTF8))
.andExpect(jsonPath("$.id", is(geoRegion.getId().intValue())))
.andExpect(jsonPath("$.name", is(geoRegion.getName())))
.andExpect(jsonPath("$.isoCode", is(geoRegion.getIsoCode())))
.andExpect(jsonPath("$.parentRegion.isoCode", is(geoRegion.getParentRegion().getIsoCode())))
.andExpect(jsonPath("$.countries[0].code3", is(country.getCode3())))
.andExpect(jsonPath("$.subRegions", hasSize(0)));
}
private Country setupCountry(String isoCode, String name){
Country country = new Country();
country.setCode3(isoCode);
country.setName(name);
country.setCurrent(true);
return countryRepository.save(country);
}
private GeoRegion setupRegion(String isoCode, String name, Country country, GeoRegion parentRegion) {
GeoRegion region = new GeoRegion();
region.setCountries(Collections.singletonList(country));
region.setIsoCode(isoCode);
region.setName(name);
region.setParentRegion(parentRegion);
return geoRegionRepository.save(region);
}
private Accession setupAccession() {
Accession a = new Accession();
a.setAccessionId(new AccessionId());
a.setInstitute(setupInstitute("INS001"));
a.setAccessionNumber("ACC001");
a.setCountryOfOrigin(country);
Taxonomy2 taxon = new Taxonomy2();
taxon.setGenus("Hordeum");
a.setTaxonomy(taxonomyService.ensureTaxonomy(taxon));
return accessionRepository.save(a);
}
private FaoInstitute setupInstitute(String instCode){
FaoInstitute institute = new FaoInstitute();
institute.setCode(instCode);
institute.setCountry(country);
institute.setAccessionCount(1);
institute.setPgrActivity(true);
return instituteRepository.save(institute);
}
}
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment