{"action":"created","comment":{"url":"https://api.github.com/repos/AtlasOfLivingAustralia/specieslist-webapp/pulls/comments/27270007","id":27270007,"diff_hunk":"@@ -324,4 +327,96 @@ class WebServiceController {\n             render status:400, text: 'Required param not provided: email'\n         }\n     }\n+\n+    /**\n+     * Lists all unique keys from the key value pairs of all records owned by the requested data resource(s)\n+     *\n+     * @param druid one or more DR UIDs (comma-separated if there are more than 1)\n+     * @return JSON list of unique key names\n+     */\n+    def listKeys() {\n+        if (!params.druid) {\n+            response.status = HttpStatus.SC_BAD_REQUEST\n+            response.sendError(HttpStatus.SC_BAD_REQUEST, \"Must provide a comma-separated list of druid value(s).\")\n+        } else {\n+            List<String> druids = params.druid.split(\",\")\n+\n+            def kvps = SpeciesListKVP.withCriteria {\n+                'in'(\"dataResourceUid\", druids)\n+\n+                projections {\n+                    distinct(\"key\")\n+                }\n+\n+                order(\"key\")\n+            }\n+\n+            render kvps as JSON\n+        }\n+    }\n+\n+    /**\n+     * Finds species list items that contains specific keys\n+     *\n+     * @param druid one or more DR UIDs (comma-separated if there are more than 1). Mandatory.\n+     * @param keys one or more KVP keys (comma-separated if there are more than 1). Mandatory.\n+     * @param format either 'json' or 'csv'. Optional - defaults to json. Controls the output format.\n+     *\n+     * @return if format = json, {scientificName1: [{key: key1, value: value1}, ...], scientificName2: [{key: key1, value: value1}, ...]}. If format = csv, returns a CSV download with columns [ScientificName,Key1,Key2...].\n+     */\n+    def listItemsByKeys() {\n+        if (!params.druid || !params.keys) {\n+            response.status = HttpStatus.SC_BAD_REQUEST\n+            response.sendError(HttpStatus.SC_BAD_REQUEST, \"Must provide a comma-separated list of druid value(s) and a comma-separated list of key(s). Parameter 'format' is optional ('json' or 'csv').\")\n+        } else {\n+            List<String> druids = params.druid.split(\",\")\n+            List<String> keys = params.keys.split(\",\")\n+\n+            def listItems = SpeciesListItem.withCriteria {\n+                'in'(\"dataResourceUid\", druids)\n+                kvpValues {\n+                    'in'(\"key\", keys)\n+                }\n+\n+                order(\"rawScientificName\")\n+            }\n+\n+            Map<String, List> results = [:]\n+\n+            listItems.each {\n+                if (!results[it.rawScientificName]) {\n+                    results[it.rawScientificName] = []\n+                }\n+                List kvps = []\n+                it.kvpValues.each {\n+                    if (keys.contains(it.key)) {\n+                        kvps << [key: it.key, value: it.value]\n+                    }\n+                }\n+                results[it.rawScientificName] = kvps","path":"grails-app/controllers/au/org/ala/specieslist/WebServiceController.groovy","position":null,"original_position":82,"commit_id":"30191b855be096ec07cccb65f2cb8a7ba0828146","original_commit_id":"7141c850bcea61b365f1cd7d3050f86235e10631","user":{"login":"m-r-c","id":7333671,"avatar_url":"https://avatars.githubusercontent.com/u/7333671?v=3","gravatar_id":"","url":"https://api.github.com/users/m-r-c","html_url":"https://github.com/m-r-c","followers_url":"https://api.github.com/users/m-r-c/followers","following_url":"https://api.github.com/users/m-r-c/following{/other_user}","gists_url":"https://api.github.com/users/m-r-c/gists{/gist_id}","starred_url":"https://api.github.com/users/m-r-c/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/m-r-c/subscriptions","organizations_url":"https://api.github.com/users/m-r-c/orgs","repos_url":"https://api.github.com/users/m-r-c/repos","events_url":"https://api.github.com/users/m-r-c/events{/privacy}","received_events_url":"https://api.github.com/users/m-r-c/received_events","type":"User","site_admin":false},"body":"Well spotted. Fixed.","created_at":"2015-03-27T00:56:45Z","updated_at":"2015-03-27T00:56:45Z","html_url":"https://github.com/AtlasOfLivingAustralia/specieslist-webapp/pull/30#discussion_r27270007","pull_request_url":"https://api.github.com/repos/AtlasOfLivingAustralia/specieslist-webapp/pulls/30","_links":{"self":{"href":"https://api.github.com/repos/AtlasOfLivingAustralia/specieslist-webapp/pulls/comments/27270007"},"html":{"href":"https://github.com/AtlasOfLivingAustralia/specieslist-webapp/pull/30#discussion_r27270007"},"pull_request":{"href":"https://api.github.com/repos/AtlasOfLivingAustralia/specieslist-webapp/pulls/30"}}},"pull_request":{"url":"https://api.github.com/repos/AtlasOfLivingAustralia/specieslist-webapp/pulls/30","id":32073816,"html_url":"https://github.com/AtlasOfLivingAustralia/specieslist-webapp/pull/30","diff_url":"https://github.com/AtlasOfLivingAustralia/specieslist-webapp/pull/30.diff","patch_url":"https://github.com/AtlasOfLivingAustralia/specieslist-webapp/pull/30.patch","issue_url":"https://api.github.com/repos/AtlasOfLivingAustralia/specieslist-webapp/issues/30","number":30,"state":"open","locked":false,"title":"Fixes #29 'integration with phylolink","user":{"login":"m-r-c","id":7333671,"avatar_url":"https://avatars.githubusercontent.com/u/7333671?v=3","gravatar_id":"","url":"https://api.github.com/users/m-r-c","html_url":"https://github.com/m-r-c","followers_url":"https://api.github.com/users/m-r-c/followers","following_url":"https://api.github.com/users/m-r-c/following{/other_user}","gists_url":"https://api.github.com/users/m-r-c/gists{/gist_id}","starred_url":"https://api.github.com/users/m-r-c/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/m-r-c/subscriptions","organizations_url":"https://api.github.com/users/m-r-c/orgs","repos_url":"https://api.github.com/users/m-r-c/repos","events_url":"https://api.github.com/users/m-r-c/events{/privacy}","received_events_url":"https://api.github.com/users/m-r-c/received_events","type":"User","site_admin":false},"body":"","created_at":"2015-03-27T00:13:22Z","updated_at":"2015-03-27T00:56:45Z","closed_at":null,"merged_at":null,"merge_commit_sha":"18699e734f8bb05db81b66cb857ce4d26585808e","assignee":null,"milestone":null,"commits_url":"https://api.github.com/repos/AtlasOfLivingAustralia/specieslist-webapp/pulls/30/commits","review_comments_url":"https://api.github.com/repos/AtlasOfLivingAustralia/specieslist-webapp/pulls/30/comments","review_comment_url":"https://api.github.com/repos/AtlasOfLivingAustralia/specieslist-webapp/pulls/comments{/number}","comments_url":"https://api.github.com/repos/AtlasOfLivingAustralia/specieslist-webapp/issues/30/comments","statuses_url":"https://api.github.com/repos/AtlasOfLivingAustralia/specieslist-webapp/statuses/30191b855be096ec07cccb65f2cb8a7ba0828146","head":{"label":"AtlasOfLivingAustralia:phylolink","ref":"phylolink","sha":"30191b855be096ec07cccb65f2cb8a7ba0828146","user":{"login":"AtlasOfLivingAustralia","id":7296572,"avatar_url":"https://avatars.githubusercontent.com/u/7296572?v=3","gravatar_id":"","url":"https://api.github.com/users/AtlasOfLivingAustralia","html_url":"https://github.com/AtlasOfLivingAustralia","followers_url":"https://api.github.com/users/AtlasOfLivingAustralia/followers","following_url":"https://api.github.com/users/AtlasOfLivingAustralia/following{/other_user}","gists_url":"https://api.github.com/users/AtlasOfLivingAustralia/gists{/gist_id}","starred_url":"https://api.github.com/users/AtlasOfLivingAustralia/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/AtlasOfLivingAustralia/subscriptions","organizations_url":"https://api.github.com/users/AtlasOfLivingAustralia/orgs","repos_url":"https://api.github.com/users/AtlasOfLivingAustralia/repos","events_url":"https://api.github.com/users/AtlasOfLivingAustralia/events{/privacy}","received_events_url":"https://api.github.com/users/AtlasOfLivingAustralia/received_events","type":"Organization","site_admin":false},"repo":{"id":21645417,"name":"specieslist-webapp","full_name":"AtlasOfLivingAustralia/specieslist-webapp","owner":{"login":"AtlasOfLivingAustralia","id":7296572,"avatar_url":"https://avatars.githubusercontent.com/u/7296572?v=3","gravatar_id":"","url":"https://api.github.com/users/AtlasOfLivingAustralia","html_url":"https://github.com/AtlasOfLivingAustralia","followers_url":"https://api.github.com/users/AtlasOfLivingAustralia/followers","following_url":"https://api.github.com/users/AtlasOfLivingAustralia/following{/other_user}","gists_url":"https://api.github.com/users/AtlasOfLivingAustralia/gists{/gist_id}","starred_url":"https://api.github.com/users/AtlasOfLivingAustralia/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/AtlasOfLivingAustralia/subscriptions","organizations_url":"https://api.github.com/users/AtlasOfLivingAustralia/orgs","repos_url":"https://api.github.com/users/AtlasOfLivingAustralia/repos","events_url":"https://api.github.com/users/AtlasOfLivingAustralia/events{/privacy}","received_events_url":"https://api.github.com/users/AtlasOfLivingAustralia/received_events","type":"Organization","site_admin":false},"private":false,"html_url":"https://github.com/AtlasOfLivingAustralia/specieslist-webapp","description":"Species lists tool","fork":false,"url":"https://api.github.com/repos/AtlasOfLivingAustralia/specieslist-webapp","forks_url":"https://api.github.com/repos/AtlasOfLivingAustralia/specieslist-webapp/forks","keys_url":"https://api.github.com/repos/AtlasOfLivingAustralia/specieslist-webapp/keys{/key_id}","collaborators_url":"https://api.github.com/repos/AtlasOfLivingAustralia/specieslist-webapp/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/AtlasOfLivingAustralia/specieslist-webapp/teams","hooks_url":"https://api.github.com/repos/AtlasOfLivingAustralia/specieslist-webapp/hooks","issue_events_url":"https://api.github.com/repos/AtlasOfLivingAustralia/specieslist-webapp/issues/events{/number}","events_url":"https://api.github.com/repos/AtlasOfLivingAustralia/specieslist-webapp/events","assignees_url":"https://api.github.com/repos/AtlasOfLivingAustralia/specieslist-webapp/assignees{/user}","branches_url":"https://api.github.com/repos/AtlasOfLivingAustralia/specieslist-webapp/branches{/branch}","tags_url":"https://api.github.com/repos/AtlasOfLivingAustralia/specieslist-webapp/tags","blobs_url":"https://api.github.com/repos/AtlasOfLivingAustralia/specieslist-webapp/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/AtlasOfLivingAustralia/specieslist-webapp/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/AtlasOfLivingAustralia/specieslist-webapp/git/refs{/sha}","trees_url":"https://api.github.com/repos/AtlasOfLivingAustralia/specieslist-webapp/git/trees{/sha}","statuses_url":"https://api.github.com/repos/AtlasOfLivingAustralia/specieslist-webapp/statuses/{sha}","languages_url":"https://api.github.com/repos/AtlasOfLivingAustralia/specieslist-webapp/languages","stargazers_url":"https://api.github.com/repos/AtlasOfLivingAustralia/specieslist-webapp/stargazers","contributors_url":"https://api.github.com/repos/AtlasOfLivingAustralia/specieslist-webapp/contributors","subscribers_url":"https://api.github.com/repos/AtlasOfLivingAustralia/specieslist-webapp/subscribers","subscription_url":"https://api.github.com/repos/AtlasOfLivingAustralia/specieslist-webapp/subscription","commits_url":"https://api.github.com/repos/AtlasOfLivingAustralia/specieslist-webapp/commits{/sha}","git_commits_url":"https://api.github.com/repos/AtlasOfLivingAustralia/specieslist-webapp/git/commits{/sha}","comments_url":"https://api.github.com/repos/AtlasOfLivingAustralia/specieslist-webapp/comments{/number}","issue_comment_url":"https://api.github.com/repos/AtlasOfLivingAustralia/specieslist-webapp/issues/comments{/number}","contents_url":"https://api.github.com/repos/AtlasOfLivingAustralia/specieslist-webapp/contents/{+path}","compare_url":"https://api.github.com/repos/AtlasOfLivingAustralia/specieslist-webapp/compare/{base}...{head}","merges_url":"https://api.github.com/repos/AtlasOfLivingAustralia/specieslist-webapp/merges","archive_url":"https://api.github.com/repos/AtlasOfLivingAustralia/specieslist-webapp/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/AtlasOfLivingAustralia/specieslist-webapp/downloads","issues_url":"https://api.github.com/repos/AtlasOfLivingAustralia/specieslist-webapp/issues{/number}","pulls_url":"https://api.github.com/repos/AtlasOfLivingAustralia/specieslist-webapp/pulls{/number}","milestones_url":"https://api.github.com/repos/AtlasOfLivingAustralia/specieslist-webapp/milestones{/number}","notifications_url":"https://api.github.com/repos/AtlasOfLivingAustralia/specieslist-webapp/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/AtlasOfLivingAustralia/specieslist-webapp/labels{/name}","releases_url":"https://api.github.com/repos/AtlasOfLivingAustralia/specieslist-webapp/releases{/id}","created_at":"2014-07-09T08:44:35Z","updated_at":"2015-03-24T21:13:51Z","pushed_at":"2015-03-27T00:56:16Z","git_url":"git://github.com/AtlasOfLivingAustralia/specieslist-webapp.git","ssh_url":"git@github.com:AtlasOfLivingAustralia/specieslist-webapp.git","clone_url":"https://github.com/AtlasOfLivingAustralia/specieslist-webapp.git","svn_url":"https://github.com/AtlasOfLivingAustralia/specieslist-webapp","homepage":"http://lists.ala.org.au","size":11946,"stargazers_count":0,"watchers_count":0,"language":"Groovy","has_issues":true,"has_downloads":true,"has_wiki":true,"has_pages":false,"forks_count":4,"mirror_url":null,"open_issues_count":9,"forks":4,"open_issues":9,"watchers":0,"default_branch":"master"}},"base":{"label":"AtlasOfLivingAustralia:master","ref":"master","sha":"56a81c6674a0b5dd89aebaae8f2dd476a59acee7","user":{"login":"AtlasOfLivingAustralia","id":7296572,"avatar_url":"https://avatars.githubusercontent.com/u/7296572?v=3","gravatar_id":"","url":"https://api.github.com/users/AtlasOfLivingAustralia","html_url":"https://github.com/AtlasOfLivingAustralia","followers_url":"https://api.github.com/users/AtlasOfLivingAustralia/followers","following_url":"https://api.github.com/users/AtlasOfLivingAustralia/following{/other_user}","gists_url":"https://api.github.com/users/AtlasOfLivingAustralia/gists{/gist_id}","starred_url":"https://api.github.com/users/AtlasOfLivingAustralia/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/AtlasOfLivingAustralia/subscriptions","organizations_url":"https://api.github.com/users/AtlasOfLivingAustralia/orgs","repos_url":"https://api.github.com/users/AtlasOfLivingAustralia/repos","events_url":"https://api.github.com/users/AtlasOfLivingAustralia/events{/privacy}","received_events_url":"https://api.github.com/users/AtlasOfLivingAustralia/received_events","type":"Organization","site_admin":false},"repo":{"id":21645417,"name":"specieslist-webapp","full_name":"AtlasOfLivingAustralia/specieslist-webapp","owner":{"login":"AtlasOfLivingAustralia","id":7296572,"avatar_url":"https://avatars.githubusercontent.com/u/7296572?v=3","gravatar_id":"","url":"https://api.github.com/users/AtlasOfLivingAustralia","html_url":"https://github.com/AtlasOfLivingAustralia","followers_url":"https://api.github.com/users/AtlasOfLivingAustralia/followers","following_url":"https://api.github.com/users/AtlasOfLivingAustralia/following{/other_user}","gists_url":"https://api.github.com/users/AtlasOfLivingAustralia/gists{/gist_id}","starred_url":"https://api.github.com/users/AtlasOfLivingAustralia/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/AtlasOfLivingAustralia/subscriptions","organizations_url":"https://api.github.com/users/AtlasOfLivingAustralia/orgs","repos_url":"https://api.github.com/users/AtlasOfLivingAustralia/repos","events_url":"https://api.github.com/users/AtlasOfLivingAustralia/events{/privacy}","received_events_url":"https://api.github.com/users/AtlasOfLivingAustralia/received_events","type":"Organization","site_admin":false},"private":false,"html_url":"https://github.com/AtlasOfLivingAustralia/specieslist-webapp","description":"Species lists tool","fork":false,"url":"https://api.github.com/repos/AtlasOfLivingAustralia/specieslist-webapp","forks_url":"https://api.github.com/repos/AtlasOfLivingAustralia/specieslist-webapp/forks","keys_url":"https://api.github.com/repos/AtlasOfLivingAustralia/specieslist-webapp/keys{/key_id}","collaborators_url":"https://api.github.com/repos/AtlasOfLivingAustralia/specieslist-webapp/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/AtlasOfLivingAustralia/specieslist-webapp/teams","hooks_url":"https://api.github.com/repos/AtlasOfLivingAustralia/specieslist-webapp/hooks","issue_events_url":"https://api.github.com/repos/AtlasOfLivingAustralia/specieslist-webapp/issues/events{/number}","events_url":"https://api.github.com/repos/AtlasOfLivingAustralia/specieslist-webapp/events","assignees_url":"https://api.github.com/repos/AtlasOfLivingAustralia/specieslist-webapp/assignees{/user}","branches_url":"https://api.github.com/repos/AtlasOfLivingAustralia/specieslist-webapp/branches{/branch}","tags_url":"https://api.github.com/repos/AtlasOfLivingAustralia/specieslist-webapp/tags","blobs_url":"https://api.github.com/repos/AtlasOfLivingAustralia/specieslist-webapp/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/AtlasOfLivingAustralia/specieslist-webapp/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/AtlasOfLivingAustralia/specieslist-webapp/git/refs{/sha}","trees_url":"https://api.github.com/repos/AtlasOfLivingAustralia/specieslist-webapp/git/trees{/sha}","statuses_url":"https://api.github.com/repos/AtlasOfLivingAustralia/specieslist-webapp/statuses/{sha}","languages_url":"https://api.github.com/repos/AtlasOfLivingAustralia/specieslist-webapp/languages","stargazers_url":"https://api.github.com/repos/AtlasOfLivingAustralia/specieslist-webapp/stargazers","contributors_url":"https://api.github.com/repos/AtlasOfLivingAustralia/specieslist-webapp/contributors","subscribers_url":"https://api.github.com/repos/AtlasOfLivingAustralia/specieslist-webapp/subscribers","subscription_url":"https://api.github.com/repos/AtlasOfLivingAustralia/specieslist-webapp/subscription","commits_url":"https://api.github.com/repos/AtlasOfLivingAustralia/specieslist-webapp/commits{/sha}","git_commits_url":"https://api.github.com/repos/AtlasOfLivingAustralia/specieslist-webapp/git/commits{/sha}","comments_url":"https://api.github.com/repos/AtlasOfLivingAustralia/specieslist-webapp/comments{/number}","issue_comment_url":"https://api.github.com/repos/AtlasOfLivingAustralia/specieslist-webapp/issues/comments{/number}","contents_url":"https://api.github.com/repos/AtlasOfLivingAustralia/specieslist-webapp/contents/{+path}","compare_url":"https://api.github.com/repos/AtlasOfLivingAustralia/specieslist-webapp/compare/{base}...{head}","merges_url":"https://api.github.com/repos/AtlasOfLivingAustralia/specieslist-webapp/merges","archive_url":"https://api.github.com/repos/AtlasOfLivingAustralia/specieslist-webapp/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/AtlasOfLivingAustralia/specieslist-webapp/downloads","issues_url":"https://api.github.com/repos/AtlasOfLivingAustralia/specieslist-webapp/issues{/number}","pulls_url":"https://api.github.com/repos/AtlasOfLivingAustralia/specieslist-webapp/pulls{/number}","milestones_url":"https://api.github.com/repos/AtlasOfLivingAustralia/specieslist-webapp/milestones{/number}","notifications_url":"https://api.github.com/repos/AtlasOfLivingAustralia/specieslist-webapp/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/AtlasOfLivingAustralia/specieslist-webapp/labels{/name}","releases_url":"https://api.github.com/repos/AtlasOfLivingAustralia/specieslist-webapp/releases{/id}","created_at":"2014-07-09T08:44:35Z","updated_at":"2015-03-24T21:13:51Z","pushed_at":"2015-03-27T00:56:16Z","git_url":"git://github.com/AtlasOfLivingAustralia/specieslist-webapp.git","ssh_url":"git@github.com:AtlasOfLivingAustralia/specieslist-webapp.git","clone_url":"https://github.com/AtlasOfLivingAustralia/specieslist-webapp.git","svn_url":"https://github.com/AtlasOfLivingAustralia/specieslist-webapp","homepage":"http://lists.ala.org.au","size":11946,"stargazers_count":0,"watchers_count":0,"language":"Groovy","has_issues":true,"has_downloads":true,"has_wiki":true,"has_pages":false,"forks_count":4,"mirror_url":null,"open_issues_count":9,"forks":4,"open_issues":9,"watchers":0,"default_branch":"master"}},"_links":{"self":{"href":"https://api.github.com/repos/AtlasOfLivingAustralia/specieslist-webapp/pulls/30"},"html":{"href":"https://github.com/AtlasOfLivingAustralia/specieslist-webapp/pull/30"},"issue":{"href":"https://api.github.com/repos/AtlasOfLivingAustralia/specieslist-webapp/issues/30"},"comments":{"href":"https://api.github.com/repos/AtlasOfLivingAustralia/specieslist-webapp/issues/30/comments"},"review_comments":{"href":"https://api.github.com/repos/AtlasOfLivingAustralia/specieslist-webapp/pulls/30/comments"},"review_comment":{"href":"https://api.github.com/repos/AtlasOfLivingAustralia/specieslist-webapp/pulls/comments{/number}"},"commits":{"href":"https://api.github.com/repos/AtlasOfLivingAustralia/specieslist-webapp/pulls/30/commits"},"statuses":{"href":"https://api.github.com/repos/AtlasOfLivingAustralia/specieslist-webapp/statuses/30191b855be096ec07cccb65f2cb8a7ba0828146"}}}}