Commit 335881bf authored by Maxym Borodenko's avatar Maxym Borodenko
Browse files

Taxonomy2: Support manual configuration of GRIN Taxonomy references

parent efb18aee
......@@ -19,7 +19,7 @@ import java.io.Serializable;
import java.util.Iterator;
import com.fasterxml.jackson.annotation.JsonInclude;
import org.genesys.blocks.model.filters.BasicModelFilter;
import org.genesys.blocks.model.filters.EmptyModelFilter;
import org.springframework.data.domain.Page;
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
......@@ -40,7 +40,7 @@ public class FilteredPage<T> implements Iterable<T>, Serializable {
public Page<T> page;
/** The filter. */
public BasicModelFilter<?, ?> filter;
public EmptyModelFilter<?, ?> filter;
/** The filter code. */
@JsonInclude(JsonInclude.Include.NON_EMPTY)
......@@ -52,7 +52,7 @@ public class FilteredPage<T> implements Iterable<T>, Serializable {
* @param filter the filter
* @param data the data
*/
public FilteredPage(final BasicModelFilter<?, ?> filter, final Page<T> data) {
public FilteredPage(final EmptyModelFilter<?, ?> filter, final Page<T> data) {
this.filter = filter;
this.page = data;
}
......@@ -64,7 +64,7 @@ public class FilteredPage<T> implements Iterable<T>, Serializable {
* @param filter the filter
* @param data the data
*/
public FilteredPage(final String filterCode, final BasicModelFilter<?, ?> filter, final Page<T> data) {
public FilteredPage(final String filterCode, final EmptyModelFilter<?, ?> filter, final Page<T> data) {
this.filterCode = filterCode;
this.filter = filter;
this.page = data;
......
......@@ -24,8 +24,11 @@ import org.genesys2.server.api.FilteredPage;
import org.genesys2.server.api.Pagination;
import org.genesys2.server.exception.NotFoundElement;
import org.genesys2.server.model.genesys.Taxonomy2;
import org.genesys2.server.model.grin.TaxonomySpecies;
import org.genesys2.server.service.TaxonomyService;
import org.genesys2.server.service.filter.TaxonomyExtraFilter;
import org.genesys2.server.service.filter.TaxonomyFilter;
import org.genesys2.server.service.filter.TaxonomySpeciesFilter;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Sort;
import org.springframework.http.MediaType;
......@@ -35,6 +38,7 @@ import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
/**
......@@ -84,7 +88,31 @@ public class TaxonomyController extends ApiBaseController {
* @return the page
*/
@PostMapping(value = "/list", produces = { MediaType.APPLICATION_JSON_VALUE })
public FilteredPage<TaxonomyService.Taxonomy2Info> listTaxonomies(final Pagination page, @RequestBody final TaxonomyFilter filter) {
public FilteredPage<TaxonomyService.Taxonomy2Info> listTaxonomies(final Pagination page, @RequestBody final TaxonomyExtraFilter filter) {
return new FilteredPage<>(filter, taxonomyService.list(filter, page.toPageRequest(100, Sort.Direction.ASC, "genus", "species", "id")));
}
/**
* List taxonomies species.
*
* @param page the page
* @param filter the filter
* @return the page
*/
@PostMapping(value = "/grin-species", produces = { MediaType.APPLICATION_JSON_VALUE })
public FilteredPage<TaxonomySpecies> listSpecies(final Pagination page, @RequestBody final TaxonomySpeciesFilter filter) {
return new FilteredPage<>(filter, taxonomyService.listSpecies(filter, page.toPageRequest(100, Sort.Direction.ASC, "id")));
}
/**
* Sets GRIN species to taxonomy2.
*
* @param taxonomy2Id the ID of Taxonomy2
* @param customGrinSpeciesId the ID of GRIN TaxonomySpecies
* @return updated record of Taxonomy2
*/
@PostMapping(value = "/set-grin-species/{id}", produces = { MediaType.APPLICATION_JSON_VALUE })
public Taxonomy2 setGrinSpecies(@PathVariable("id") final long taxonomy2Id, @RequestParam(required = false, value = "customGrinSpeciesId") final Long customGrinSpeciesId) {
return taxonomyService.setGrinSpecies(taxonomy2Id, customGrinSpeciesId);
}
}
......@@ -23,8 +23,11 @@ import org.genesys2.server.api.FilteredPage;
import org.genesys2.server.api.Pagination;
import org.genesys2.server.exception.NotFoundElement;
import org.genesys2.server.model.genesys.Taxonomy2;
import org.genesys2.server.model.grin.TaxonomySpecies;
import org.genesys2.server.service.TaxonomyService;
import org.genesys2.server.service.filter.TaxonomyExtraFilter;
import org.genesys2.server.service.filter.TaxonomyFilter;
import org.genesys2.server.service.filter.TaxonomySpeciesFilter;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Sort;
import org.springframework.http.MediaType;
......@@ -34,6 +37,7 @@ import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
/**
......@@ -83,7 +87,31 @@ public class TaxonomyController extends ApiBaseController {
* @return the page
*/
@PostMapping(value = "/list", produces = { MediaType.APPLICATION_JSON_VALUE })
public FilteredPage<TaxonomyService.Taxonomy2Info> listTaxonomies(final Pagination page, @RequestBody final TaxonomyFilter filter) {
public FilteredPage<TaxonomyService.Taxonomy2Info> listTaxonomies(final Pagination page, @RequestBody final TaxonomyExtraFilter filter) {
return new FilteredPage<>(filter, taxonomyService.list(filter, page.toPageRequest(100, Sort.Direction.ASC, "genus", "species", "id")));
}
/**
* List taxonomies species.
*
* @param page the page
* @param filter the filter
* @return the page
*/
@PostMapping(value = "/grin-species", produces = { MediaType.APPLICATION_JSON_VALUE })
public FilteredPage<TaxonomySpecies> listSpecies(final Pagination page, @RequestBody final TaxonomySpeciesFilter filter) {
return new FilteredPage<>(filter, taxonomyService.listSpecies(filter, page.toPageRequest(100, Sort.Direction.ASC, "id")));
}
/**
* Sets GRIN species to taxonomy2.
*
* @param taxonomy2Id the ID of Taxonomy2
* @param customGrinSpeciesId the ID of GRIN TaxonomySpecies
* @return updated record of Taxonomy2
*/
@PostMapping(value = "/set-grin-species/{id}", produces = { MediaType.APPLICATION_JSON_VALUE })
public Taxonomy2 setGrinSpecies(@PathVariable("id") final long taxonomy2Id, @RequestParam(required = false, value = "customGrinSpeciesId") final Long customGrinSpeciesId) {
return taxonomyService.setGrinSpecies(taxonomy2Id, customGrinSpeciesId);
}
}
......@@ -32,6 +32,7 @@ import javax.persistence.Table;
import javax.persistence.Transient;
import javax.persistence.UniqueConstraint;
import com.fasterxml.jackson.annotation.JsonIgnore;
import org.apache.commons.lang3.StringUtils;
import org.genesys2.server.model.GlobalVersionedAuditedModel;
import org.genesys2.server.model.grin.TaxonomySpecies;
......@@ -240,6 +241,11 @@ public class Taxonomy2 extends GlobalVersionedAuditedModel {
spAuthor, subtaxa, subtAuthor);
}
@ManyToOne(cascade = {}, fetch = FetchType.EAGER, optional = true)
@JoinColumn(name = "overrideTaxonomySpecies")
@JsonIgnore
private TaxonomySpecies overrideTaxonomySpecies;
/**
* Clean up nulls and stuff...
......@@ -298,4 +304,12 @@ public class Taxonomy2 extends GlobalVersionedAuditedModel {
public TaxonomySpecies getCurrentTaxonomySpecies() {
return currentTaxonomySpecies;
}
public TaxonomySpecies getOverrideTaxonomySpecies() {
return overrideTaxonomySpecies;
}
public void setOverrideTaxonomySpecies(TaxonomySpecies overrideTaxonomySpecies) {
this.overrideTaxonomySpecies = overrideTaxonomySpecies;
}
}
......@@ -21,7 +21,10 @@ import java.util.List;
import com.fasterxml.jackson.annotation.JsonUnwrapped;
import org.genesys2.server.model.genesys.Taxonomy2;
import org.genesys2.server.model.grin.TaxonomySpecies;
import org.genesys2.server.service.filter.TaxonomyExtraFilter;
import org.genesys2.server.service.filter.TaxonomyFilter;
import org.genesys2.server.service.filter.TaxonomySpeciesFilter;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
......@@ -47,7 +50,11 @@ public interface TaxonomyService {
List<Taxonomy2> list(TaxonomyFilter filter);
Page<Taxonomy2Info> list(TaxonomyFilter filter, Pageable page);
Page<Taxonomy2Info> list(TaxonomyExtraFilter filter, Pageable page);
Page<TaxonomySpecies> listSpecies(TaxonomySpeciesFilter filter, Pageable page);
Taxonomy2 setGrinSpecies(long taxonomy2Id, Long customGrinSpeciesId);
List<String> getAllGenera();
......
/*
* Copyright 2020 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.service.filter;
import java.util.List;
import java.util.Set;
import com.querydsl.core.types.Predicate;
import com.querydsl.core.types.dsl.EntityPathBase;
import org.apache.commons.collections4.CollectionUtils;
import org.genesys.blocks.model.filters.DateFilter;
import org.genesys.blocks.model.filters.EmptyModelFilter;
import org.genesys2.server.model.grin.CooperatorOwnedModel;
import org.genesys2.server.model.grin.QCooperatorOwnedModel;
/**
* {@link CooperatorOwnedModel} match by sample filters.
*
* @param <T> the generic type
* @param <R> the generic type
*/
public abstract class CooperatorOwnedModelFilter<T extends CooperatorOwnedModelFilter<T, R>, R extends CooperatorOwnedModel> extends EmptyModelFilter<T, R> {
/** The created by. */
public Set<Long> createdBy;
/** The created date. */
public DateFilter createdDate;
/** The last modified by. */
public Set<Long> modifiedBy;
/** The last modified date. */
public DateFilter modifiedDate;
/** The owned by. */
public Set<Long> ownedBy;
/** The owned date. */
public DateFilter ownedDate;
/**
* Collects list of filter predicates
*
* @param instance the instance of Q-type of <em>R</em>
* @param cooperatorOwnedModel the cooperator owned model
* @return list of predicates
*/
protected List<Predicate> collectPredicates(final EntityPathBase<R> instance, final QCooperatorOwnedModel cooperatorOwnedModel) {
List<Predicate> predicates = super.collectPredicates(instance);
if (CollectionUtils.isNotEmpty(createdBy)) {
predicates.add(cooperatorOwnedModel.createdById.in(createdBy));
}
if (CollectionUtils.isNotEmpty(modifiedBy)) {
predicates.add(cooperatorOwnedModel.modifiedById.in(modifiedBy));
}
if (CollectionUtils.isNotEmpty(ownedBy)) {
predicates.add(cooperatorOwnedModel.ownedById.in(ownedBy));
}
if (createdDate != null) {
predicates.add(createdDate.buildQuery(cooperatorOwnedModel.createdDate));
}
if (modifiedDate != null) {
predicates.add(modifiedDate.buildQuery(cooperatorOwnedModel.modifiedDate));
}
if (ownedDate != null) {
predicates.add(ownedDate.buildQuery(cooperatorOwnedModel.ownedDate));
}
return predicates;
}
}
/*
* Copyright 2020 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.service.filter;
import java.util.List;
import com.querydsl.core.types.Predicate;
import org.genesys2.server.model.genesys.QTaxonomy2;
import org.genesys2.server.model.genesys.Taxonomy2;
/**
* Extra filters for {@link Taxonomy2}.
*/
public class TaxonomyExtraFilter extends TaxonomyFilter {
/** The overrides. */
public Boolean overrides;
/** The grin. */
public Boolean grin;
/**
* Builds the query.
*
* @return the predicate
*/
public List<Predicate> collectPredicates() {
return super.collectPredicates();
}
/**
* Builds the query.
*
* @param taxonomy2 the taxonomy2
* @return the boolean builder
*/
public List<Predicate> collectPredicates(final QTaxonomy2 taxonomy2) {
final List<Predicate> predicates = super.collectPredicates(taxonomy2);
if (overrides != null) {
if (overrides) {
predicates.add(taxonomy2.overrideTaxonomySpecies.isNotNull());
} else {
predicates.add(taxonomy2.overrideTaxonomySpecies.isNull());
}
}
if (grin != null) {
if (grin) {
predicates.add(taxonomy2.grinTaxonomySpecies.isNotNull());
} else {
predicates.add(taxonomy2.grinTaxonomySpecies.isNull());
}
}
return predicates;
}
}
/*
* Copyright 2020 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.service.filter;
import java.util.List;
import java.util.Set;
import com.querydsl.core.types.Predicate;
import org.apache.commons.collections4.CollectionUtils;
import org.genesys.blocks.model.filters.StringFilter;
import org.genesys2.server.model.grin.QTaxonomySpecies;
import org.genesys2.server.model.grin.TaxonomySpecies;
/**
* Filters for {@link TaxonomySpecies}.
*/
public class TaxonomySpeciesFilter extends CooperatorOwnedModelFilter<TaxonomySpeciesFilter, TaxonomySpecies> implements IFullTextFilter {
/** Any text. */
public String _text;
/** The genus. */
public Set<String> genus;
/** The species. */
public Set<String> species;
/** The subtaxa. */
public StringFilter subtaxa;
/**
* Builds the query.
*
* @return the predicate
*/
@Override
public List<Predicate> collectPredicates() {
return collectPredicates(QTaxonomySpecies.taxonomySpecies);
}
/**
* Builds the query.
*
* @param taxonomySpecies the taxonomySpecies
* @return the boolean builder
*/
public List<Predicate> collectPredicates(final QTaxonomySpecies taxonomySpecies) {
final List<Predicate> predicates = super.collectPredicates(taxonomySpecies, taxonomySpecies._super);
if (CollectionUtils.isNotEmpty(genus)) {
predicates.add(taxonomySpecies.genusSpecies.in(genus));
}
if (CollectionUtils.isNotEmpty(species)) {
predicates.add(taxonomySpecies.speciesName.in(species));
}
if (subtaxa != null) {
predicates.add(subtaxa.buildQuery(taxonomySpecies.subtaxa));
}
return predicates;
}
@Override
public String get_text() {
return _text;
}
}
......@@ -22,14 +22,18 @@ import java.util.Set;
import java.util.stream.Collectors;
import org.apache.commons.lang3.StringUtils;
import org.genesys2.server.exception.NotFoundElement;
import org.genesys2.server.model.genesys.QTaxonomy2;
import org.genesys2.server.model.genesys.Taxonomy2;
import org.genesys2.server.model.grin.TaxonomySpecies;
import org.genesys2.server.persistence.AccessionRepository;
import org.genesys2.server.persistence.Taxonomy2Repository;
import org.genesys2.server.persistence.grin.TaxonomyGenusRepository;
import org.genesys2.server.persistence.grin.TaxonomySpeciesRepository;
import org.genesys2.server.service.TaxonomyService;
import org.genesys2.server.service.filter.TaxonomyExtraFilter;
import org.genesys2.server.service.filter.TaxonomyFilter;
import org.genesys2.server.service.filter.TaxonomySpeciesFilter;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
......@@ -223,8 +227,7 @@ public class TaxonomyServiceImpl implements TaxonomyService {
}
@Override
@PreAuthorize("hasRole('ADMINISTRATOR')")
public Page<Taxonomy2Info> list(TaxonomyFilter filter, Pageable page) {
public Page<Taxonomy2Info> list(TaxonomyExtraFilter filter, Pageable page) {
final BooleanBuilder predicate = new BooleanBuilder();
if (filter != null) {
predicate.and(filter.buildPredicate());
......@@ -242,6 +245,35 @@ public class TaxonomyServiceImpl implements TaxonomyService {
return new PageImpl<>(content, page, res.getTotalElements());
}
@Override
public Page<TaxonomySpecies> listSpecies(TaxonomySpeciesFilter filter, Pageable page) {
final BooleanBuilder predicate = new BooleanBuilder();
if (filter != null) {
predicate.and(filter.buildPredicate());
}
Page<TaxonomySpecies> res = grinSpeciesRepository.findAll(predicate, page);
return new PageImpl<>(res.getContent(), page, res.getTotalElements());
}
@Override
@Transactional
@PreAuthorize("hasRole('ADMINISTRATOR')")
public Taxonomy2 setGrinSpecies(long taxonomy2Id, Long customGrinSpeciesId) {
Taxonomy2 taxonomy2 = taxonomy2Repository.findById(taxonomy2Id).orElseThrow(() -> new NotFoundElement("No such Taxonomy2"));
if (customGrinSpeciesId == null) {
taxonomy2.setGrinTaxonomySpecies(null);
taxonomy2.setCurrentTaxonomySpecies(null);
taxonomy2.setOverrideTaxonomySpecies(null);
} else {
TaxonomySpecies grinSpecies = grinSpeciesRepository.findById(customGrinSpeciesId).orElseThrow(() -> new NotFoundElement("No such TaxonomySpecies"));
taxonomy2.setOverrideTaxonomySpecies(grinSpecies);
taxonomy2.setGrinTaxonomySpecies(grinSpecies);
taxonomy2.setCurrentTaxonomySpecies(grinSpecies.getCurrentTaxonomySpecies());
}
return taxonomy2Repository.save(taxonomy2);
}
@Override
public List<String> getAllGenera() {
return taxonomy2Repository.getAllGenera();
......
......@@ -155,11 +155,21 @@ public class Taxonomy2GRINMatcher {
final List<IGrinSpecies> speciesRows = taxonomyDatabase.findSpeciesRow(genus, species, StringUtils.defaultIfBlank(subtaxa, null));
if (speciesRows.size() == 1) {
final IGrinSpecies speciesRow = speciesRows.get(0);
taxonomy.setGrinTaxonomySpecies(new TaxonomySpecies(speciesRow.getSpeciesId()));
taxonomy.setCurrentTaxonomySpecies(new TaxonomySpecies(speciesRow.getCurrentTaxonomySpeciesId()));
if (taxonomy.getOverrideTaxonomySpecies() == null || speciesRow.getSpeciesId().equals(taxonomy.getOverrideTaxonomySpecies().getId())) {
taxonomy.setGrinTaxonomySpecies(new TaxonomySpecies(speciesRow.getSpeciesId()));
taxonomy.setCurrentTaxonomySpecies(new TaxonomySpecies(speciesRow.getCurrentTaxonomySpeciesId()));
taxonomy.setOverrideTaxonomySpecies(null);
} else {
// Don't touch!
}
} else {
taxonomy.setGrinTaxonomySpecies(null);
LOG.debug("Multiple speciesRows match genus={} species={} subtaxa={}", genus, species, subtaxa);
if (taxonomy.getOverrideTaxonomySpecies() == null) {
// Set GRIN species to null
taxonomy.setGrinTaxonomySpecies(null);
taxonomy.setCurrentTaxonomySpecies(null);
}
}
}
}
......
......@@ -7323,3 +7323,24 @@ databaseChangeLog:
cascadeConstraints: true
tableName: croprule
- changeSet:
id: 1598865413069-1
author: mborodenko
changes:
- addColumn:
columns:
- column:
name: overrideTaxonomySpecies
type: BIGINT
tableName: taxonomy2
- addForeignKeyConstraint:
baseColumnNames: overrideTaxonomySpecies
baseTableName: taxonomy2
constraintName: FKn3la99r9gncvprp581vsn8fs7
deferrable: false
initiallyDeferred: false
onDelete: NO ACTION
onUpdate: NO ACTION
referencedColumnNames: taxonomy_species_id
referencedTableName: grin_species
validate: true
......@@ -19,9 +19,17 @@ package org.genesys.test.server.api;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotNull;
import java.util.Date;
import java.util.concurrent.atomic.AtomicInteger;
import org.genesys.test.base.AbstractApiTest;
import org.genesys2.server.model.genesys.Taxonomy2;
import org.genesys2.server.model.grin.CooperatorOwnedModel;
import org.genesys2.server.model.grin.TaxonomyGenus;
import org.genesys2.server.model.grin.TaxonomySpecies;
import org.genesys2.server.persistence.Taxonomy2Repository;
import org.genesys2.server.persistence.grin.TaxonomyGenusRepository;
import org.genesys2.server.persistence.grin.TaxonomySpeciesRepository;
import org.genesys2.server.service.TaxonomyService;
import org.junit.After;
import org.junit.Before;
......@@ -37,9 +45,21 @@ public abstract class AbstractTaxonomyControllerTest extends AbstractApiTest {
protected TaxonomyService taxonomyService;
@Autowired
protected Taxonomy2Repository taxonomyRepository;
@Autowired
protected TaxonomyGenusRepository taxonomyGenusRepository;
@Autowired
protected TaxonomySpeciesRepository taxonomySpeciesRepository;
private final AtomicInteger grinGenusId = new AtomicInteger(1);
private final AtomicInteger grinSpeciesId = new AtomicInteger(1);
protected static final String GENUS_1 = "Abelia";
protected static final String GENUS_2 = "Hordeum";
protected static final String GRINSPECIES_SPECIES_NAME_1 = "alpina";
protected static final String GRINSPECIES_NAME_1 = "Clematis alpina";