From 6587d73e49eb89b5bffb43d6bd00e19f9fe4de44 Mon Sep 17 00:00:00 2001 From: Patricia Koh Date: Tue, 7 Jul 2020 14:31:23 +1000 Subject: [PATCH 1/9] Bump up to next snapshot version --- CollectoryGrailsPlugin.groovy | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CollectoryGrailsPlugin.groovy b/CollectoryGrailsPlugin.groovy index 8033945f..adf38c03 100644 --- a/CollectoryGrailsPlugin.groovy +++ b/CollectoryGrailsPlugin.groovy @@ -9,7 +9,7 @@ class CollectoryGrailsPlugin { def authenticateService // the plugin version - def version = "1.9.9" + def version = "1.9.10-SNAPSHOT" // the version or versions of Grails the plugin is designed for def grailsVersion = "2.5 > *" // resources that are excluded from plugin packaging From ee18cc4a6a6627f753d4bdb9aaeb3a4a8a88fe3a Mon Sep 17 00:00:00 2001 From: Patricia Koh Date: Tue, 4 Aug 2020 15:25:31 +1000 Subject: [PATCH 2/9] https://github.com/AtlasOfLivingAustralia/collectory-plugin/issues/167 - Changes for setting isShareableWithGbif flag to false --- .../au/org/ala/collectory/IptController.groovy | 3 ++- .../services/au/org/ala/collectory/CrudService.groovy | 9 +++++++-- .../services/au/org/ala/collectory/IptService.groovy | 11 ++++++----- 3 files changed, 15 insertions(+), 8 deletions(-) diff --git a/grails-app/controllers/au/org/ala/collectory/IptController.groovy b/grails-app/controllers/au/org/ala/collectory/IptController.groovy index 657428e9..3bfaee9b 100644 --- a/grails-app/controllers/au/org/ala/collectory/IptController.groovy +++ b/grails-app/controllers/au/org/ala/collectory/IptController.groovy @@ -39,6 +39,7 @@ class IptController { def create = params.create != null && params.create.equalsIgnoreCase("true") def check = params.check == null || !params.check.equalsIgnoreCase("false") def keyName = params.key ?: 'catalogNumber' + def isShareableWithGBIF = params.isShareableWithGBIF ? params.isShareableWithGBIF.toBoolean(): true def provider = ProviderGroup._get(params.uid) def apiKey = request.cookies.find { cookie -> cookie.name == API_KEY_COOKIE } def keyCheck = apiKey ? collectoryAuthService.checkApiKey(apiKey.value) : null @@ -55,7 +56,7 @@ class IptController { return } try { - def updates = provider == null ? null : iptService.scan(provider, create, check, keyName, username, admin) + def updates = provider == null ? null : iptService.scan(provider, create, check, keyName, username, admin, isShareableWithGBIF) log.info "${updates.size()} data resources to update for ${params.uid}" response.addHeader HttpHeaders.VARY, HttpHeaders.ACCEPT withFormat { diff --git a/grails-app/services/au/org/ala/collectory/CrudService.groovy b/grails-app/services/au/org/ala/collectory/CrudService.groovy index 11645eab..bc829c74 100644 --- a/grails-app/services/au/org/ala/collectory/CrudService.groovy +++ b/grails-app/services/au/org/ala/collectory/CrudService.groovy @@ -36,7 +36,7 @@ class CrudService { 'filed','publicArchiveAvailable','contentTypes','defaultDarwinCoreValues', 'imageMetadata', 'geographicDescription','northBoundingCoordinate','southBoundingCoordinate','eastBoundingCoordinate', 'westBoundingCoordinate','beginDate','endDate','qualityControlDescription','methodStepDescription', - 'gbifDoi' + 'gbifDoi', 'isShareableWithGBIF' ] static dataResourceNumberProperties = ['harvestFrequency','downloadLimit'] static dataResourceTimestampProperties = ['lastChecked','dataCurrency'] @@ -414,7 +414,12 @@ class CrudService { dataResourceStringProperties.each { if (obj.has(it)) { - dr."${it}" = obj."${it}".toString() + if (dr."${it}" instanceof Boolean && obj."${it}" instanceof Boolean) { + dr."${it}" = obj."${it}" + } else { + dr."${it}" = obj."${it}".toString() + } + } } diff --git a/grails-app/services/au/org/ala/collectory/IptService.groovy b/grails-app/services/au/org/ala/collectory/IptService.groovy index 171c8944..ce13a905 100644 --- a/grails-app/services/au/org/ala/collectory/IptService.groovy +++ b/grails-app/services/au/org/ala/collectory/IptService.groovy @@ -81,9 +81,9 @@ class IptService { * @return A list of data resources that need re-loading */ @org.springframework.transaction.annotation.Transactional(propagation = org.springframework.transaction.annotation.Propagation.REQUIRED) - def scan(DataProvider provider, boolean create, boolean check, String keyName, String username, boolean admin) { + def scan(DataProvider provider, boolean create, boolean check, String keyName, String username, boolean admin, boolean shareWithGbif) { ActivityLog.log username, admin, provider.uid, Action.SCAN - def updates = this.rss(provider, keyName) + def updates = this.rss(provider, keyName, shareWithGbif) return merge(provider, updates, create, check, username, admin) } @@ -166,7 +166,7 @@ class IptService { * * @return A list of (possibly new providers) */ - def rss(DataProvider provider, String keyName) { + def rss(DataProvider provider, String keyName, Boolean isShareableWithGBIF) { def url = provider.websiteUrl if(!url.endsWith("/")){ @@ -180,7 +180,7 @@ class IptService { rss.declareNamespace(NAMESPACES) def items = rss.channel.item - return items.collect { item -> this.createDataResource(provider, item, keyName) } + return items.collect { item -> this.createDataResource(provider, item, keyName, isShareableWithGBIF) } } /** @@ -192,7 +192,7 @@ class IptService { * * @return A created resource matching the information provided */ - def createDataResource(DataProvider provider, GPathResult rssItem, String keyName) { + def createDataResource(DataProvider provider, GPathResult rssItem, String keyName, Boolean isShareableWithGBIF) { def resource = new DataResource() def eml = rssItem."ipt:eml"?.text() def dwca = rssItem."ipt:dwca"?.text() @@ -201,6 +201,7 @@ class IptService { rssFields.each { name, accessor -> resource.setProperty(name, accessor(rssItem))} resource.connectionParameters = dwca == null || dwca.isEmpty() ? null : "{ \"protocol\": \"DwCA\", \"url\": \"${dwca}\", \"automation\": true, \"termsForUniqueKey\": [ \"${keyName}\" ] }"; + resource.isShareableWithGBIF = isShareableWithGBIF def contacts = [] if (eml != null) { From 7821d3bee9af783e01344c865be2ff699e754b68 Mon Sep 17 00:00:00 2001 From: Patricia Koh Date: Tue, 4 Aug 2020 15:46:46 +1000 Subject: [PATCH 3/9] https://github.com/AtlasOfLivingAustralia/ala-infrastructure/issues/669 - Access sensitive info only if there is a valid api key --- .../org/ala/collectory/DataController.groovy | 29 ++++++++++++++++++- .../au/org/ala/collectory/CrudService.groovy | 4 +-- 2 files changed, 30 insertions(+), 3 deletions(-) diff --git a/grails-app/controllers/au/org/ala/collectory/DataController.groovy b/grails-app/controllers/au/org/ala/collectory/DataController.groovy index f96fca56..bb7d91a0 100644 --- a/grails-app/controllers/au/org/ala/collectory/DataController.groovy +++ b/grails-app/controllers/au/org/ala/collectory/DataController.groovy @@ -176,6 +176,25 @@ class DataController { render(status:403, text: 'You are not authorised to use this service') } + def checkApiKey = { + def apiKey = { + if(params.api_key){ + params.api_key + } else { + request.getHeader("Authorization") + } + }.call() + def keyCheck + if (apiKey) { + keyCheck = collectoryAuthService?.checkApiKey(apiKey) + } + if (!keyCheck?.valid) { + return false + } + keyCheck.validApiKey = apiKey + return keyCheck + } + /** * Should be added for any uri that returns multiple formats based on content negotiation. * (So the content can be correctly cached by proxies.) @@ -306,6 +325,7 @@ class DataController { * @param uid - optional uid of an instance of entity * @param pg - optional instance specified by uid (added in beforeInterceptor) * @param summary - any non-null value will cause a richer summary to be returned for entity lists + * @param api_key - optional param for displaying any sensitive data */ def getEntity = { if (params.entity == 'tempDataResource') { @@ -313,11 +333,12 @@ class DataController { } else { def urlForm = params.entity def clazz = capitalise(urlForm) + def keyCheck = checkApiKey() if (params.pg) { // return specified entity addContentLocation "/ws/${urlForm}/${params.pg.uid}" def eTag = (params.pg.uid + ":" + params.pg.lastUpdated).encodeAsMD5() - def entityInJson = crudService."read${clazz}"(params.pg) + def entityInJson = crudService."read${clazz}"(params.pg, keyCheck && keyCheck.validApiKey?:null) entityInJson = metadataService.convertAnyLocalPaths(entityInJson) response.setContentType("application/json") response.setCharacterEncoding("UTF-8") @@ -602,10 +623,16 @@ class DataController { /** * Returns a single contact (independent of any entity). + * A valid api key is needed to display contact information * URI form: /contacts/{id} * @param id the database id of the contact */ def contacts = { + + if (!checkApiKey()) { + unauthorised() + return + } if (params.id) { def c = Contact.get(params.id) if (c) { diff --git a/grails-app/services/au/org/ala/collectory/CrudService.groovy b/grails-app/services/au/org/ala/collectory/CrudService.groovy index bc829c74..27d1b3fd 100644 --- a/grails-app/services/au/org/ala/collectory/CrudService.groovy +++ b/grails-app/services/au/org/ala/collectory/CrudService.groovy @@ -269,7 +269,7 @@ class CrudService { /* data resource */ - def readDataResource(DataResource p) { + def readDataResource(DataResource p, apiKey = null) { def builder = new JSONBuilder() def result = builder.build { @@ -351,7 +351,7 @@ class CrudService { if (p.listConsumers()) { linkedRecordConsumers = p.listConsumers().formatEntitiesFromUids() } - if (p.connectionParameters) { + if (p.connectionParameters && apiKey) { connectionParameters = p.connectionParameters.formatJSON() } if (p.imageMetadata) { From f558dc42c83409de24b75873db11fc169add3a50 Mon Sep 17 00:00:00 2001 From: Patricia Koh Date: Tue, 4 Aug 2020 15:56:34 +1000 Subject: [PATCH 4/9] Build branch on travis --- .travis.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.travis.yml b/.travis.yml index 681d1f93..c86977aa 100644 --- a/.travis.yml +++ b/.travis.yml @@ -7,6 +7,7 @@ branches: - master - develop - hotfix + - feature/167 before_install: - wget -q https://raw.githubusercontent.com/AtlasOfLivingAustralia/travis-build-configuration/master/ala_common.sh - chmod +x ala_common.sh From 2ecab32521e42ac2b5f772ab2b203058e4e357e4 Mon Sep 17 00:00:00 2001 From: Patricia Koh Date: Wed, 5 Aug 2020 07:47:19 +1000 Subject: [PATCH 5/9] https://github.com/AtlasOfLivingAustralia/ala-infrastructure/issues/669 - pass flag for data resource only --- .../au/org/ala/collectory/DataController.groovy | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/grails-app/controllers/au/org/ala/collectory/DataController.groovy b/grails-app/controllers/au/org/ala/collectory/DataController.groovy index bb7d91a0..ec8e2a49 100644 --- a/grails-app/controllers/au/org/ala/collectory/DataController.groovy +++ b/grails-app/controllers/au/org/ala/collectory/DataController.groovy @@ -191,8 +191,7 @@ class DataController { if (!keyCheck?.valid) { return false } - keyCheck.validApiKey = apiKey - return keyCheck + return true } /** @@ -333,12 +332,17 @@ class DataController { } else { def urlForm = params.entity def clazz = capitalise(urlForm) - def keyCheck = checkApiKey() if (params.pg) { // return specified entity addContentLocation "/ws/${urlForm}/${params.pg.uid}" def eTag = (params.pg.uid + ":" + params.pg.lastUpdated).encodeAsMD5() - def entityInJson = crudService."read${clazz}"(params.pg, keyCheck && keyCheck.validApiKey?:null) + def entityInJson + if (clazz == 'DataResource') { + def keyCheck = checkApiKey() + entityInJson = crudService."read${clazz}"(params.pg, keyCheck) + } else { + entityInJson = crudService."read${clazz}"(params.pg) + } entityInJson = metadataService.convertAnyLocalPaths(entityInJson) response.setContentType("application/json") response.setCharacterEncoding("UTF-8") From 40a9d30645135504bf5c306324d2cb4fcd0d5135 Mon Sep 17 00:00:00 2001 From: Patricia Koh Date: Thu, 6 Aug 2020 10:01:15 +1000 Subject: [PATCH 6/9] https://github.com/AtlasOfLivingAustralia/collectory-plugin/issues/167 - Use boolean property for isShareableWithGBIF flag --- .../services/au/org/ala/collectory/CrudService.groovy | 11 +++-------- 1 file changed, 3 insertions(+), 8 deletions(-) diff --git a/grails-app/services/au/org/ala/collectory/CrudService.groovy b/grails-app/services/au/org/ala/collectory/CrudService.groovy index 27d1b3fd..57d63a8d 100644 --- a/grails-app/services/au/org/ala/collectory/CrudService.groovy +++ b/grails-app/services/au/org/ala/collectory/CrudService.groovy @@ -36,11 +36,11 @@ class CrudService { 'filed','publicArchiveAvailable','contentTypes','defaultDarwinCoreValues', 'imageMetadata', 'geographicDescription','northBoundingCoordinate','southBoundingCoordinate','eastBoundingCoordinate', 'westBoundingCoordinate','beginDate','endDate','qualityControlDescription','methodStepDescription', - 'gbifDoi', 'isShareableWithGBIF' + 'gbifDoi' ] static dataResourceNumberProperties = ['harvestFrequency','downloadLimit'] static dataResourceTimestampProperties = ['lastChecked','dataCurrency'] - static dataResourceBooleanProperties = ['gbifDataset'] + static dataResourceBooleanProperties = ['gbifDataset', 'isShareableWithGBIF'] static dataResourceJSONArrays = ['connectionParameters', 'contentTypes', 'defaultDarwinCoreValues', 'imageMetadata'] //static dataResourceObjectProperties = ['dataProvider'] @@ -414,12 +414,7 @@ class CrudService { dataResourceStringProperties.each { if (obj.has(it)) { - if (dr."${it}" instanceof Boolean && obj."${it}" instanceof Boolean) { - dr."${it}" = obj."${it}" - } else { - dr."${it}" = obj."${it}".toString() - } - + dr."${it}" = obj."${it}".toString() } } From f23882b63ec6761c37156cb78f3dcb265d1e1043 Mon Sep 17 00:00:00 2001 From: Patricia Koh Date: Fri, 14 Aug 2020 14:01:31 +1000 Subject: [PATCH 7/9] https://github.com/AtlasOfLivingAustralia/collectory-plugin/issues/166 - Fixed Explore records by taxonomy Show Info page --- web-app/js/taxonTree.js | 1 - 1 file changed, 1 deletion(-) diff --git a/web-app/js/taxonTree.js b/web-app/js/taxonTree.js index dc2f4745..41e8b62d 100644 --- a/web-app/js/taxonTree.js +++ b/web-app/js/taxonTree.js @@ -158,6 +158,5 @@ function showBie(node) { if (rank == 'kingdoms') return; var name = node.attr('id'); var sppUrl = CHARTS_CONFIG.bieWebappUrl + "/species/" + name; - if (rank != 'species') { sppUrl += "_(" + rank + ")"; } document.location.href = sppUrl; } From 65ae10191630ff8a2a8998c388d27fc12d3fe54c Mon Sep 17 00:00:00 2001 From: Patricia Koh Date: Fri, 14 Aug 2020 14:05:17 +1000 Subject: [PATCH 8/9] Remove travis built on branch --- .travis.yml | 1 - 1 file changed, 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index c86977aa..681d1f93 100644 --- a/.travis.yml +++ b/.travis.yml @@ -7,7 +7,6 @@ branches: - master - develop - hotfix - - feature/167 before_install: - wget -q https://raw.githubusercontent.com/AtlasOfLivingAustralia/travis-build-configuration/master/ala_common.sh - chmod +x ala_common.sh From 3a03e9ae0a690223373907628198825d6b72d4fc Mon Sep 17 00:00:00 2001 From: Patricia Koh Date: Wed, 26 Aug 2020 07:42:09 +1000 Subject: [PATCH 9/9] Release version 1.9.10 --- CollectoryGrailsPlugin.groovy | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CollectoryGrailsPlugin.groovy b/CollectoryGrailsPlugin.groovy index adf38c03..ed9f5d8e 100644 --- a/CollectoryGrailsPlugin.groovy +++ b/CollectoryGrailsPlugin.groovy @@ -9,7 +9,7 @@ class CollectoryGrailsPlugin { def authenticateService // the plugin version - def version = "1.9.10-SNAPSHOT" + def version = "1.9.10" // the version or versions of Grails the plugin is designed for def grailsVersion = "2.5 > *" // resources that are excluded from plugin packaging