From a00cbe285e8fa1ec8a2b380e061fe103848e5989 Mon Sep 17 00:00:00 2001 From: Adam Collins Date: Wed, 3 Jan 2024 14:58:42 +1000 Subject: [PATCH] #376 rankID updates --- build.gradle | 2 +- grails-app/conf/application.yml | 9 +++- .../au/org/ala/bie/MiscController.groovy | 27 ++++++++++- .../au/org/ala/bie/ImportService.groovy | 46 +++++++++++++++---- 4 files changed, 71 insertions(+), 13 deletions(-) diff --git a/build.gradle b/build.gradle index 11388c2..d64548d 100644 --- a/build.gradle +++ b/build.gradle @@ -110,7 +110,7 @@ dependencies { } implementation "org.grails.plugins:grails-spring-websocket:2.3.0" - implementation group: "au.org.ala", name: "ala-name-matching-model", version:"4.2" + implementation group: "au.org.ala", name: "ala-name-matching-model", version:"4.3" implementation "org.jsoup:jsoup:1.15.4" implementation 'net.sf.opencsv:opencsv:2.3' implementation "org.apache.solr:solr-solrj:8.1.0" diff --git a/grails-app/conf/application.yml b/grails-app/conf/application.yml index 04c901c..72b3053 100644 --- a/grails-app/conf/application.yml +++ b/grails-app/conf/application.yml @@ -222,10 +222,17 @@ vernacularListsUrl: /default-vernacular-lists.json # Location of locality keywords (null for default) localityKeywordsUrl: /default-locality-keywords.json #nationalSpeciesDatasets: dr2699,dr2700,dr2702,dr2704,dr2703,dr3118 -defaultDownloadFields: guid,rank,scientificName,scientificNameAuthorship,taxonomicStatus,establishmentMeans,rk_genus,rk_family,rk_order,rk_class,rk_phylum,rk_kingdom,datasetName,parentGuid,acceptedConceptName,acceptedConceptID,idxtype,name + +# all available rk_ and rkid_ fields in SOLR are added to defaultDownloadFields when no rk_ field is defined in defaultDownloadFields +defaultDownloadFields: guid,rank,scientificName,scientificNameAuthorship,taxonomicStatus,establishmentMeans,datasetName,parentGuid,acceptedConceptName,acceptedConceptID,idxtype,name +downloadMaxRows: 10000 + additionalResultFields: "" #toggle for the population of occurrence counts +# override the taxon ranks taxonRanksFile with an external file +taxonRanksFile: + # Score normal value (divides integer priority by the norm to give solr boosts) # SOLR additional params and connections diff --git a/grails-app/controllers/au/org/ala/bie/MiscController.groovy b/grails-app/controllers/au/org/ala/bie/MiscController.groovy index 399938b..6e06b6f 100644 --- a/grails-app/controllers/au/org/ala/bie/MiscController.groovy +++ b/grails-app/controllers/au/org/ala/bie/MiscController.groovy @@ -40,9 +40,32 @@ class MiscController { return } - // Documented in openapi.yml, not migrating to annotations because no recent use + @Operation( + method = "GET", + tags = "rank", + operationId = "ranks", + summary = "Gets a description of the ranks used to classify levels of taxa", + responses = [ + @ApiResponse( + responseCode = "200", + headers = [ + @Header(name = 'Access-Control-Allow-Headers', description = "CORS header", schema = @Schema(type = "String")), + @Header(name = 'Access-Control-Allow-Methods', description = "CORS header", schema = @Schema(type = "String")), + @Header(name = 'Access-Control-Allow-Origin', description = "CORS header", schema = @Schema(type = "String")) + ] + ) + ] + ) + @Path("/ranks") + @Produces("application/json") def ranks() { - render importService.ranks() as JSON + def indexedFields = indexService.getIndexFieldDetails().collect { + it.name.replaceAll("^[^_]+_", "") + } + def activeRanks = importService.ranks().findAll { + indexedFields.contains(it.value.rank) + } + render activeRanks as JSON } def indexFields() { diff --git a/grails-app/services/au/org/ala/bie/ImportService.groovy b/grails-app/services/au/org/ala/bie/ImportService.groovy index 994f8ab..04f9f5f 100644 --- a/grails-app/services/au/org/ala/bie/ImportService.groovy +++ b/grails-app/services/au/org/ala/bie/ImportService.groovy @@ -1594,6 +1594,15 @@ class ImportService implements GrailsConfigurationAware { } } + def getTaxonRankID(taxonRanks, taxonRank) { + def tr = taxonRanks.get(taxonRank) + if (!tr) { + tr = taxonRanks.find { it.value.otherNames?.contains(taxonRank) } + } + + return tr ? tr.rankID : -1 + } + def buildTaxonRecord(Record record, Map doc, Map attributionMap, Map datasetMap, Map taxonRanks, String defaultTaxonomicStatus, String defaultDatasetName) { def datasetID = record.value(DwcTerm.datasetID) def taxonRank = (record.value(DwcTerm.taxonRank) ?: "").toLowerCase() @@ -1602,7 +1611,9 @@ class ImportService implements GrailsConfigurationAware { def scientificNameAuthorship = record.value(DwcTerm.scientificNameAuthorship) def nameComplete = record.value(ALATerm.nameComplete) def nameFormatted = record.value(ALATerm.nameFormatted) - def taxonRankID = taxonRanks.get(taxonRank) ? taxonRanks.get(taxonRank).rankID : -1 + // TODO: use ALATerm.taxonRankID, or the alternative, when it exists in ala-name-matching-model + //def taxonRankID = record.value(ALATerm.taxonRankID) ?: getTaxonRankID(taxonRanks, taxonRank) + def taxonRankID = getTaxonRankID(taxonRanks, taxonRank) def taxonomicStatus = record.value(DwcTerm.taxonomicStatus) ?: defaultTaxonomicStatus def nameType = record.value(GbifTerm.nameType) String taxonRemarks = record.value(DwcTerm.taxonRemarks) @@ -2942,15 +2953,32 @@ class ImportService implements GrailsConfigurationAware { * @return */ def ranks() { - JsonSlurper slurper = new JsonSlurper() - def ranks = slurper.parse(this.class.getResource("/taxonRanks.json")) - def idMap = [:] - def iter = ranks.iterator() - while (iter.hasNext()) { - def entry = iter.next() - idMap.put(entry.rank, entry) + String path = grailsApplication.config.taxonRanksFile + File taxonRanksFile = new File(path) + if (path && taxonRanksFile.exists()) { + JsonSlurper slurper = new JsonSlurper() + def ranks = slurper.parse(taxonRanksFile.text) + def idMap = [:] + def iter = ranks.iterator() + while (iter.hasNext()) { + def entry = iter.next() + idMap.put(entry.rank, entry) + } + idMap + } else { + def idMap = [:] + RankType.values().each { rankType -> + idMap.put(rankType.field, [ + branch: null, + notes: null, + otherNames: [], + rank: rankType.field, + rankGroup: rankType.cbRank?.name()?.toLowerCase(), + rankID: rankType.sortOrder + ]) + } + idMap } - idMap } /**