From 7f1869bc2cf7168d61c1cac0784721313f95c8ac Mon Sep 17 00:00:00 2001 From: Christopher Tyrrell <43977100+cdtyrrell@users.noreply.github.com> Date: Mon, 14 Aug 2023 09:18:10 -0500 Subject: [PATCH] sync tyrrell-dev with tyrrell-master (local) (#8) * Hotfix: Occurrence upload, Key editor, Taxon Profile - Resolve issue with occurrence-taxon indexing code - Only build sciname from taxon units if all units are mapped - Resolve issue with ID Key editor not displaying characters that are not grouped -Taxon Profile insert issue * Hotfix 2023 06 03 (#508) * Occurrence Upload adjustment - Trim off delimiters that are left on the beginning or end of filter string to ensure that null values are not included * Collection Listing bug fix - Collection categories failing to be persist * Occurrence Image Submissions issue resolution - Set default image sort order to 40 for observations to ensure that preserved specimen images do not take precedence * Image Processing bug - collection identifier (collid) failed to be passed to statistics update function * Resolve Taxonomy Harvester issues - Improve TROPICOS method of matching on infraspecific taxa - Improve close match suggestions * Update .gitignore * Hotfix 2023 06 19 (#518) * Taxonomy Harvesting minor adjustments - Check resources before interpretation and again after interpretation - If name is matched within one recourse, skip the unnecessary step to check other resources - Synchronize display text * Refactor ImageLocalProcessor and resolve various bugs - Provide support for input file to include medium and thumbnail image derivatives - Expand Image Map processing to allow mapping file to include any images table field name - Expand images insert function to handle any valid field found within images table - Merge duplicate actions into shared private functions - MD5 hash large version of image input file, but don't overwrite hash if supplied by source, unless image is not modified by upload scripts - Handle BOM characters at start of csv file. - Trim header elements for testing column names. - Enforce default action of accepting derivative urls supplied within a csv image map file - Improve uriExists function - Make sure to remove staging images * Occurrence Public Display page - Allow occurrence archive (deleted occurrences) to be searchable by GUID (occurrenceID, recordID), thus reporting when a record is deleted * Checklist multi-polygon map Issue - Multipolygons defined within a checklist fail to map within both simple and dynamic maps * Suppress geo ref index during stats update * Occurrence Reviewer bug - Fix for field name and start and end date filter variables failing to be carried forward when advancing to pages beyond 1000 records https://github.com/BioKIC/Symbiota/issues/335 * Collection metadata editor bug - Reset contact array to ensure that JSON string is standardized as a non-associated array Resolves issue: https://github.com/BioKIC/Symbiota/issues/487 --------- Co-authored-by: Greg Post * Add vouchers step 1 New cl voucher tab; language support; get method for checklistvoucheradmin to check if cl is associated with external service * Toggle inputs if no ext. service * Various in-progress steps (non-functional) * Hotfix 2023 07 22 (#559) * Hotfix - 2023-07-22 - DwcArchivePublishing: Material Sample publishing bug - DwC-A upload: Scientific name failed to be built when taxonomic data is supplied by by individual components - Taxonomic autocomplete: Allow autocomplete handle apostrophes - Checklist Display: Bug fix that interfered with display of linked voucher images - Checklist Manager: Checklist taxon search autocomplete failed to include higher taxa (parent data) - Taxonomy Harvester bug: F-dex harvest failed to grab parents when source was not "Index Fungorum" - Specimen Upload: Set version data changes as the default action only when a collection is live managed - Occurrence Search Harvest: Reworked search form validation to be more efficient; Fix bug with occurrence attribute checkbox/radio failing to be recognized as a selected component * Hotfix 2023-06-19 (#518) - Taxonomy Harvesting: Don't check following taxonomic resource on a positive match and input; synchronize display text - Refactor ImageLocalProcessor: -- Provide support for input file to include medium and thumbnail image derivatives -- Expand Image Map processing to allow mapping file to include any images table field name -- Expand images insert function to handle any valid field found within images table -- MD5 hash large version of image input file, but don't overwrite hash if supplied by source -- Handle BOM characters at start of csv file. -- Trim header elements for testing column names. -- Enforce default action of accepting derivative urls supplied within a csv image map file -- Make sure to remove staging images - Occurrence Public Display: Allow occurrence archive (deleted occurrences) to be searchable by GUID (occurrenceID, recordID), thus reporting when a record is deleted - Checklist multi-polygon Map: resolve Multipolygons failing to map within both simple and dynamic maps - Occurrence Reviewer: Fix for field name and start and end date filter variables failing to be carried forward when advancing to pages beyond 1000 records - Collection metadata editor: Reset contact array to ensure that JSON string is standardized as a non-associated array --------- Co-authored-by: Greg Post * Hotfix 2023 07 31 (#564) hotfix 2023-07-31 * Glossary issues - Allow terms search to do a double wildcard search to expand functionality and resolve issue with zero return when html tags (e.g. italic) are included with the terms - Remove restrictions and unnecessary default actions associated with unset language and taxon terms so that thesaurus better functions as a single language glossaries - Fix various issues with export of report when there is a single language glossary and/or terms are not linked to specific taxa - Fix issue report export not including full list when terms have complex language relationships - Improve file naming and content/layout of Word report export - Resolve issues with inclusion of all Spanish language translation files - Include translations for some missed terms * Occurrence editor - Fix bug with year, month, day field failing to null when eventDate is nulled out - allow tidInterpreted value to be transferred when scientific name is added to form via duplicate tool * Occurrence Search - Fix issue with autocomplete failing to return names that contain single or double quotes - Fix issue taxon name search failing to return correct data when name contains single or double quotes - Map Search: resolved issue where map recenters in the middle of the ocean when a search returns no coordinates * Taxonomy issues and bugs - Taxonomy Utilities: Fix issue interfering import of taxa with hybrid symbol when there is not a space between symbol and name units - Taxonomy Harvesting: Resolve 'Unranked" taxonRank designations when taxon is a non-accepted genus - Taxonomy Upload: Minor adjustments needed to support processing of taxa immediately adjacent to kingdom rank * Hotfix 2023 08 08 (#569) * Occurrence Search bug - Resolve issue with sanitation of occurrence search variables held within session storage --------- Co-authored-by: Edward Gilbert Co-authored-by: Greg Post --- checklists/checklistadminmeta.php | 19 ++- checklists/externalvouchers.php | 132 ++++++++++++++++++++ checklists/voucheradmin.php | 3 +- classes/ChecklistVoucherAdmin.php | 14 ++- content/lang/checklists/voucheradmin.en.php | 3 + content/lang/checklists/voucheradmin.es.php | 2 + content/lang/checklists/voucheradmin.fr.php | 2 + js/symb/checklists.externalserviceapi.js | 25 +++- 8 files changed, 192 insertions(+), 8 deletions(-) create mode 100644 checklists/externalvouchers.php diff --git a/checklists/checklistadminmeta.php b/checklists/checklistadminmeta.php index 4755d42de7..76798d2635 100644 --- a/checklists/checklistadminmeta.php +++ b/checklists/checklistadminmeta.php @@ -122,6 +122,19 @@ function openMappingPolyAid() { mapWindow=open("/checklists/tools/mappolyaid.php?clid=&formname=editclmatadata&latname=latcentroid&longname=longcentroid&latdef="+latDec+"&lngdef="+lngDec,"mapaid","resizable=0,width=1000,height=800,left=20,top=20"); if(mapWindow.opener == null) mapWindow.opener = self; } + + function enableDisableExtServiceFields() { + let xsrv = document.getElementById('externalservice'); + let xsid = document.getElementById('externalserviceid'); + let xstaxonfilter = document.getElementById('externalserviceiconictaxon'); + if(xsrv.value == '') { + xsid.setAttribute("disabled",""); + xstaxonfilter.setAttribute("disabled",""); + } else { + xsid.removeAttribute("disabled"); + xstaxonfilter.removeAttribute("disabled"); + } + }

- @@ -189,10 +202,10 @@ function openMappingPolyAid() {

- +

- +
diff --git a/checklists/externalvouchers.php b/checklists/externalvouchers.php new file mode 100644 index 0000000000..a895ef38d0 --- /dev/null +++ b/checklists/externalvouchers.php @@ -0,0 +1,132 @@ +setClid($clid); + $clVoucherManager->setClid($clid); + //$clVoucherManager->setCollectionVariables(); +} + +$isEditor = 0; +if($IS_ADMIN || (array_key_exists('ClAdmin', $USER_RIGHTS) && in_array($clid, $USER_RIGHTS['ClAdmin']))){ + $isEditor = 1; +} +if($isEditor){ + $taxaArray = $clManager->getTaxaList(); + ?> +
+
+
+
+ +
+
+ + '; + $prevGroup = ''; + foreach($taxaArray as $tid => $sppArr){ + $group = $sppArr['taxongroup']; + if($group != $prevGroup){ + $famUrl = '../taxa/index.php?taxauthid=1&taxon='.strip_tags($group).'&clid='.$clid; + //Edit family name display style here + ?> +
+ +
+ '; + echo ''; + echo ' '; + //class="taxon-span" + ?> + + + + + + + \n"; + $scinameasid = str_replace(" ", "-", $sppArr['sciname']); + if($arrforexternalserviceapi == '') { + $arrforexternalserviceapi .= "'" . $scinameasid . "'"; + } else { + $arrforexternalserviceapi .= ",'" . $scinameasid . "'"; + } + } + echo '
'; + //if(isset($dynamPropsArr) && $dynamPropsArr['externalservice'] == 'inaturalist') { + echo ''; + ?> + + +
+
+
+
+ \ No newline at end of file diff --git a/checklists/voucheradmin.php b/checklists/voucheradmin.php index c2c2fcd674..724a6e4447 100644 --- a/checklists/voucheradmin.php +++ b/checklists/voucheradmin.php @@ -235,7 +235,8 @@
  • - getAssociatedExternalService()) echo '
  • ' . $LANG['EXTVOUCH'] . '
  • '; if($clManager->hasVoucherProjects()) echo '
  • '.(isset($LANG['ADDIMGV'])?$LANG['ADDIMGV']:'Add Image Voucher').'
  • '; ?>
  • diff --git a/classes/ChecklistVoucherAdmin.php b/classes/ChecklistVoucherAdmin.php index 50a255834c..77c1d7103f 100644 --- a/classes/ChecklistVoucherAdmin.php +++ b/classes/ChecklistVoucherAdmin.php @@ -44,7 +44,7 @@ public function setClid($clid){ private function setMetaData(){ if($this->clid){ $sql = 'SELECT clid, name, locality, publication, abstract, authors, parentclid, notes, latcentroid, longcentroid, pointradiusmeters, '. - 'footprintwkt, access, defaultSettings, dynamicsql, datelastmodified, uid, type, initialtimestamp '. + 'footprintwkt, access, defaultSettings, dynamicsql, datelastmodified, dynamicProperties, uid, type, initialtimestamp '. 'FROM fmchecklists WHERE (clid = '.$this->clid.')'; $rs = $this->conn->query($sql); if($rs){ @@ -66,6 +66,7 @@ private function setMetaData(){ $this->clMetadata["defaultSettings"] = $row->defaultSettings; $this->clMetadata["dynamicsql"] = $row->dynamicsql; $this->clMetadata["datelastmodified"] = $row->datelastmodified; + $this->clMetadata['dynamicProperties'] = $row->dynamicProperties; } $rs->free(); } @@ -108,6 +109,17 @@ public function getPolygonCoordinates(){ return $retArr; } + public function getAssociatedExternalService(){ + $resp = 'FALSE'; + if($this->clMetadata['dynamicProperties']){ + $dynpropArr = json_decode($this->clMetadata['dynamicProperties'], TRUE); + if(array_key_exists('externalservice', $dynpropArr)) { + $resp = $dynpropArr['externalservice']; + } + } + return $resp; + } + //Dynamic query variable functions public function setCollectionVariables(){ if($this->clid){ diff --git a/content/lang/checklists/voucheradmin.en.php b/content/lang/checklists/voucheradmin.en.php index ed482da629..702bcd5986 100644 --- a/content/lang/checklists/voucheradmin.en.php +++ b/content/lang/checklists/voucheradmin.en.php @@ -31,6 +31,8 @@ $LANG['NON_VOUCHERED'] = 'Non-Vouchered Taxa'; $LANG['MISSINGTAXA'] = 'Missing Taxa'; $LANG['VOUCHCONF'] = 'Voucher Conflicts'; +$LANG['EXTVOUCH'] = 'Add Vouchers from an External Service (e.g., iNaturalist)'; +$LANG['LINKEXT'] = 'Link external vouchers'; $LANG['REPORTS'] = 'Reports'; $LANG['NONVOUCHTAX'] = 'Non-vouchered taxa list'; $LANG['OCCURNONVOUCH'] = 'Occurrences for non-vouchered taxa'; @@ -44,6 +46,7 @@ $LANG['LISTEDBELOWARESPECINSTRUC'] = 'Listed below are species from the checklist that do not have linked specimen vouchers. Click on name to use the search statement above to dynamically query the occurrence dataset for possible voucher specimens. Use the pulldown to the right to display the specimens in a table format.'; +$LANG['LISTEDBELOWEXTERNAL'] = "Listed below are species from the checklist. Using the search functions from the external website, locate an observation that will serve as a possible voucher for each taxon. Copy the observation's ID (for example, from the last portion of the URL) and paste it in the corresponding text box. Multiple vouchers may be added for each taxon; use commas to separate the ID numbers."; $LANG['ALLTAXACONTAINVOUCH'] = 'All taxa contain voucher links'; $LANG['ADDITIONAL'] = 'See the Option Panel on the central page for more versatile export and print options that dynamically incorporate option selections'; $LANG['FULLSPECLIST'] = 'Full species list (CSV)'; diff --git a/content/lang/checklists/voucheradmin.es.php b/content/lang/checklists/voucheradmin.es.php index a3e1afc6cd..44c7b36226 100644 --- a/content/lang/checklists/voucheradmin.es.php +++ b/content/lang/checklists/voucheradmin.es.php @@ -31,6 +31,7 @@ $LANG['NON_VOUCHERED'] = 'Taxa sin Vouchers'; $LANG['MISSINGTAXA'] = 'Taxa Faltantes'; $LANG['VOUCHCONF'] = 'Voucher Conflictivos'; +$LANG['EXTVOUCH'] = 'Connectar Vouchers desde un Servicio Externo (por ejemplo, iNaturalist)'; $LANG['REPORTS'] = 'Reportes'; $LANG['NONVOUCHTAX'] = 'Listado de Taxa sin vouchers'; $LANG['OCCURNONVOUCH'] = 'Ocurrencias para taxa sin vouchers'; @@ -44,6 +45,7 @@ $LANG['LISTEDBELOWARESPECINSTRUC'] = 'A continuación se enumeran las especies de la lista de control que no han sido vinculadas a espécimenes voucher. Haga clic en el nombre para utilizar la instrucción de búsqueda de arriba para consultar de forma dinámica el conjunto de datos de ocurrencia de especímenes voucher posibles. Utilice la lista desplegable a la derecha para mostrar los especímenes en un formato de tabla.'; +$LANG['LISTEDBELOWEXTERNAL'] = "A continuación se enumeran las especies de la lista. Usando las funciones de búsqueda del sitio web externo, localice una observación que le sirva como posible comprobante para cada taxón. Copie el ID de la observación (por ejemplo, de la última parte de la URL) y péguelo en el cuadro de texto correspondiente. Se pueden agregar múltiples comprobantes para cada taxón; utilice comas para separar los números de identificación."; $LANG['ALLTAXACONTAINVOUCH'] = 'Todos los taxones contienen enlaces a vouchers'; $LANG['ADDITIONAL'] = 'Consulte el Panel de opciones en la página central para obtener opciones adicionales de exportación e impresión que incorporan dinámicamente selecciones de opciones.'; $LANG['FULLSPECLIST'] = 'Listado de especies completo (CSV)'; diff --git a/content/lang/checklists/voucheradmin.fr.php b/content/lang/checklists/voucheradmin.fr.php index ab68190807..706cd113d6 100644 --- a/content/lang/checklists/voucheradmin.fr.php +++ b/content/lang/checklists/voucheradmin.fr.php @@ -31,6 +31,7 @@ $LANG['NON_VOUCHERED'] = 'Taxons sans Échantillons'; $LANG['MISSINGTAXA'] = 'Taxons Manquants'; $LANG['VOUCHCONF'] = 'Conflits Échantillons'; +$LANG['EXTVOUCH'] = "Connecter Échantillons d'un Service Externe (par exemple, iNaturalist)"; $LANG['REPORTS'] = 'Rapports'; $LANG['NONVOUCHTAX'] = 'Liste des Taxons sans Échantillons'; $LANG['OCCURNONVOUCH'] = 'Occurrences pour les Taxons sans Échantillons'; @@ -44,6 +45,7 @@ $LANG['LISTEDBELOWARESPECINSTRUC'] = "Ci-dessous figurent les espèces de la liste qui n'ont pas d'échantillons liés.. Cliquez sur le nom pour utiliser l'instruction de recherche ci-dessus pour interroger dynamiquement l'ensemble de données pour des échantillons possibles. Utilisez le menu déroulant à droite pour afficher les échantillons sous forme de tableau."; +$LANG['LISTEDBELOWEXTERNAL'] = "Vous trouverez ci-dessous les espèces de la liste. À l'aide des fonctions de recherche du site Web externe, localisez une observation qui servira de référence possible pour chaque taxon. Copiez l'ID de l'observation (par exemple, à partir de la dernière partie de l'URL) et collez-le dans la zone de texte correspondante. Plusieurs bons peuvent être ajoutés pour chaque taxon; utilisez des virgules pour séparer les numéros d'identification."; $LANG['ALLTAXACONTAINVOUCH'] = 'Tous les taxons contiennent des échantillons'; $LANG['ADDITIONAL'] = "Voir le panneau d'options sur la page centrale pour des options d'exportation et d'impression supplémentaires qui intègrent dynamiquement des sélections d'options"; $LANG['FULLSPECLIST'] = 'Liste complète des espèces (CSV)'; diff --git a/js/symb/checklists.externalserviceapi.js b/js/symb/checklists.externalserviceapi.js index 9a775a0cfc..9c3b5d11e9 100644 --- a/js/symb/checklists.externalserviceapi.js +++ b/js/symb/checklists.externalserviceapi.js @@ -17,6 +17,8 @@ function extractiNatTaxaIdAndName(resultsjson) { return outputArr; } +// Note: as of the time of coding, iNaturalist API v2 is in beta and this section may require some adjusting post-release. +// API v1 does not allow custom fields (i.e., taxa names) to be returned. async function fetchiNatPage1(projID, iconictaxon = '', qualitygrade = 'research') { let apiurl = ''; if(iconictaxon == '') { @@ -65,10 +67,8 @@ async function fetchiNatAdditionalPages(loopnum, projID, iconictaxon = '', quali async function iNatPlotPoints(llbounds, projID, iconictaxon = '', qualitygrade = 'research', rank = 'species') { let apiurl = ''; - - if(iconictaxon == '') { - // add something here to switch to API v1 if v2 fails? + // add something here to switch to API v2 if v1 fails? apiurl = `https://api.inaturalist.org/v1/points/${zoom}/${xtile}/${ytile}.grid.json?mappable=true&project_id=${projID}&rank=${rank}&quality_grade=${qualitygrade}&order=asc&order_by=updated_at`; } else { apiurl = `https://api.inaturalist.org/v1/points/${zoom}/${xtile}/${ytile}.grid.json?mappable=true&project_id=${projID}&rank=${rank}&iconic_taxa=${iconictaxon}&quality_grade=${qualitygrade}&order=asc&order_by=updated_at`; @@ -83,6 +83,25 @@ async function iNatPlotPoints(llbounds, projID, iconictaxon = '', qualitygrade = console.error(err); } } + + +async function iNatGetVoucher(obsID) { + let apiurl = `https://api.inaturalist.org/v1/observation`; //ADD NECESSARY CODE TO RETURN species, user, number, date + const resp = await fetch(apiurl); + try { + if(resp.ok) { + const obsjson = await resp.json(); + return obsjson; + } + } catch(err) { + console.error(err); + } +} + +// LINK VOUCHER +// split on comma + + // check for an iNaturalist project id // x1. on create or update: Pull place_id from project json, then pull lat/long from place json (two calls).