kohana::lang("rest_api.authIntroduction"),
'authMethods' => kohana::lang("rest_api.authMethods"),
'resources' => kohana::lang("rest_api.resourcesTitle"),
+ 'resourcesIntro' => kohana::lang("rest_api.resourcesIntroduction"),
'filters' => kohana::lang("rest_api.filterTitle"),
'filterText' => kohana::lang("rest_api.filterText"),
'submissionFormat' => kohana::lang("rest_api.submissionFormatTitle"),
@@ -193,6 +194,7 @@ private function indexHtml($resourceConfig) {
$lang[submissionFormat]
$lang[submissionFormatText]
$lang[resources]
+$lang[resourcesIntro]
HTML;
$apiRoot = url::base() . 'index.php/services/rest';
@@ -208,6 +210,9 @@ private function indexHtml($resourceConfig) {
}
$badge = empty($endpointPathOptions['deprecated']) ? '' : ' deprecated';
$endpointOutput .= "$method $endpointPath$badge
";
+ if (!empty($endpointPathOptions['deprecated'])) {
+ $endpointOutput .= '' . kohana::lang('rest_api.deprecatedEndpoint') . '
';
+ }
$endpointOutput .= "Example URL: $apiRoot/" . str_replace(
['{id}', '{path}', '{file.xml}'],
['123', 'library/occurrences', 'filterable_explore_list.xml'],
From 8a18564b64e2516a126e4bd3de3ca8268066a3be Mon Sep 17 00:00:00 2001
From: John van Breda
Date: Thu, 25 Aug 2022 15:56:48 +0100
Subject: [PATCH 2/9] Bool params to REST api reports accept t/f
Allows autofeed to be a validated and documented param.
---
modules/rest_api/controllers/services/rest.php | 10 ++++++++--
1 file changed, 8 insertions(+), 2 deletions(-)
diff --git a/modules/rest_api/controllers/services/rest.php b/modules/rest_api/controllers/services/rest.php
index f016902e03..2c0bc39b2a 100644
--- a/modules/rest_api/controllers/services/rest.php
+++ b/modules/rest_api/controllers/services/rest.php
@@ -457,12 +457,18 @@ class Rest_Controller extends Controller {
'reports/{path}' => [],
'reports/{path}/{file.xml}' => [
'params' => [
+ 'autofeed' => [
+ 'datatype' => 'boolean',
+ ],
'filter_id' => [
'datatype' => 'integer',
],
'limit' => [
'datatype' => 'integer',
],
+ 'max_time' => [
+ 'datatype' => 'integer',
+ ],
'offset' => [
'datatype' => 'integer',
],
@@ -1776,12 +1782,12 @@ private function checkParamDatatype($paramName, &$value, array $paramDef) {
}
}
elseif ($datatype === 'boolean') {
- if (!preg_match('/^(true|false)$/', $trimmed)) {
+ if (!preg_match('/^(true|false|t|f)$/', $trimmed)) {
RestObjects::$apiResponse->fail('Bad request', 400,
"Invalid boolean for $paramName parameter, value should be true or false");
}
// Set the value to a real bool.
- $value = $trimmed === 'true';
+ $value = $trimmed === 'true' || $trimmed === 't';
}
// If a limited options set available then check the value is in the list.
if (!empty($paramDef['options']) && !in_array($trimmed, $paramDef['options'])) {
From 6e62973a41206d415482b590dfbe3dcbd63153aa Mon Sep 17 00:00:00 2001
From: John van Breda
Date: Thu, 25 Aug 2022 15:57:49 +0100
Subject: [PATCH 3/9] Documentation for autofeed and max_time
For REST Api reports that link to Logstash
---
modules/rest_api/i18n/en_GB/rest_api.php | 21 ++++++++++++++++++++-
1 file changed, 20 insertions(+), 1 deletion(-)
diff --git a/modules/rest_api/i18n/en_GB/rest_api.php b/modules/rest_api/i18n/en_GB/rest_api.php
index ff231840cb..d107d43bf5 100644
--- a/modules/rest_api/i18n/en_GB/rest_api.php
+++ b/modules/rest_api/i18n/en_GB/rest_api.php
@@ -667,7 +667,11 @@
Retrieves the contents of the folder specified by {path} of the reports directory on the warehouse.
URL.
TXT;
-$lang['resources']['GET reports/{path}/{file-xml}'] = 'Access the output for a report specified by the supplied path.';
+$lang['resources']['GET reports/{path}/{file-xml}'] = <<
Date: Thu, 25 Aug 2022 16:03:26 +0100
Subject: [PATCH 4/9] Linting
---
.../rest_api/libraries/RestApiResponse.php | 90 ++++++++++++-------
1 file changed, 58 insertions(+), 32 deletions(-)
diff --git a/modules/rest_api/libraries/RestApiResponse.php b/modules/rest_api/libraries/RestApiResponse.php
index e004083eca..bfddc043c8 100644
--- a/modules/rest_api/libraries/RestApiResponse.php
+++ b/modules/rest_api/libraries/RestApiResponse.php
@@ -19,13 +19,18 @@
* @link https://github.com/indicia-team/warehouse/
*/
+/**
+ * Class which manages responses from the REST API.
+ */
class RestApiResponse {
private $startTime;
/**
- * A template to define the header of any HTML pages output. Replace
- * {{ base }} with the root path of the warehouse.
+ * A template to define the header of any HTML pages output.
+ *
+ * Replace {{ base }} with the root path of the warehouse.
+ *
* @var string
*/
private $htmlHeader = <<<'HTML'
@@ -43,6 +48,13 @@ class RestApiResponse {
HTML;
+ /**
+ * A template to define the footer of any HTML pages output.
+ *
+ * Replace {{ base }} with the root path of the warehouse.
+ *
+ * @var string
+ */
private $htmlFooter = <<<'HTML'
@@ -64,14 +76,14 @@ class RestApiResponse {
*
* @var bool
*/
- public $wantIndex = false;
+ public $wantIndex = FALSE;
/**
* Include empty output cells in HTML?
*
* @var bool
*/
- public $includeEmptyValues = true;
+ public $includeEmptyValues = TRUE;
/**
* Index method which provides top level help for the API resource endpoints.
@@ -98,7 +110,7 @@ public function index(array $resourceConfig) {
* Configuration for the list of available resources and the methods they
* support.
*/
- private function indexHtml($resourceConfig) {
+ private function indexHtml(array $resourceConfig) {
// Output an HTML page header.
echo str_replace('{{ base }}', url::base(), $this->htmlHeader);
$lang = [
@@ -147,7 +159,7 @@ private function indexHtml($resourceConfig) {
elseif ($value === TRUE) {
$key .= 'false';
}
- else {
+ else {
$key .= json_encode($value);
}
$optionTexts[] = '' . kohana::lang($key) . '';
@@ -405,6 +417,7 @@ public function getUrlWithCurrentParams($url) {
/**
* Echos a successful response in HTML format.
+ *
* @param array $data
* @param array $options
*/
@@ -418,11 +431,11 @@ private function succeedHtml($data, $options) {
$this->outputArrayAsHtml($options['metadata']);
}
- // output an index table if present for this output
+ // Output an index table if present for this output.
if ($this->wantIndex && isset($data['data'])) {
echo $this->getIndexAsHtml($data['data']);
}
- // output the main response body
+ // Output the main response body.
if (isset($options['metadata']) || !empty($this->responseTitle)) {
echo 'Response
';
}
@@ -432,14 +445,19 @@ private function succeedHtml($data, $options) {
elseif (is_object($data)) {
$options['preprocess'] = true;
// We are returning a single row from the database.
- $this->outputResultAsHtml(array($data), $options);
+ $this->outputResultAsHtml([$data], $options);
}
echo str_replace('{{ base }}', url::base(), $this->htmlFooter);
}
/**
- * For some resources when output as HTML, we insert an index into the top of the page.
- * @return string HTML for the index.
+ * Insert an HTML index.
+ *
+ * For some resources when output as HTML, we insert an index into the top of
+ * the page.
+ *
+ * @return string
+ * HTML for the index.
*/
private function getIndexAsHtml($data) {
$r = '';
@@ -472,13 +490,15 @@ private function getIndexAsHtml($data) {
}
/**
- * Dumps out a nested array as a nested HTML table. Used to output response data when the
- * format type requested is HTML.
+ * Dumps out a nested array as a nested HTML table.
+ *
+ * Used to output response data when the format type requested is HTML.
*
- * @param array $array Data to output
+ * @param array $array
+ * Data to output
* @param array $options
*/
- private function outputArrayAsHtml($array, $options = array()) {
+ private function outputArrayAsHtml($array, $options = []) {
if (count($array)) {
$id = isset($options['tableId']) ? " id=\"$options[tableId]\"" : '';
echo "";
@@ -490,36 +510,39 @@ private function outputArrayAsHtml($array, $options = array()) {
echo "$label";
}
$keys = array_keys($array);
- $col1 = is_integer($keys[0]) ? 'Row' : 'Field';
- $col2 = is_integer($keys[0]) ? 'Record' : 'Value';
+ $col1 = is_int($keys[0]) ? 'Row' : 'Field';
+ $col2 = is_int($keys[0]) ? 'Record' : 'Value';
$this->preProcessRow($array, $options);
echo "$col1 | $col2 | ";
echo '';
- foreach ($array as $key=>$value) {
- if (empty($value) && !$this->includeEmptyValues)
+ foreach ($array as $key => $value) {
+ if (empty($value) && !$this->includeEmptyValues) {
continue;
- // If in a simple list of data or pg output, start preprocessing rows. Other structural output elements are not
- // preprocessed.
+ }
+ // If in a simple list of data or pg output, start preprocessing rows.
+ // Other structural output elements are not preprocessed.
$options['preprocess'] = is_int($key) || is_object($value);
$class = is_array($value) && !empty($value['type']) ? " class=\"type-$value[type]\"" : '';
echo "$key | ";
$options['tableId'] = $key;
- // Object data here means a pg result object. Or, if it is an non-associative array so a simple list, then
- // output as a table rather than a nested structure.
+ // Object data here means a pg result object. Or, if it is an
+ // non-associative array so a simple list, then output as a table
+ // rather than a nested structure.
if (is_object($value) || (is_array($value) && count($value) > 0 && is_int(array_keys($value)[0]))) {
// recurse into pg result data
$this->outputResultAsHtml($value, $options);
}
elseif (is_array($value)) {
- // recurse into plain array data
+ // Recurse into plain array data.
$this->outputArrayAsHtml($value, $options);
}
else {
- // a simple value to output. If it contains an internal link then process it to hide user/secret data.
+ // A simple value to output. If it contains an internal link then
+ // process it to hide user/secret data.
if (preg_match('/^http(s)?:\/\//', $value)) {
$parts = explode('?', $value);
$displayUrl = $parts[0];
- if (count($parts)>1) {
+ if (count($parts) > 1) {
parse_str($parts[1], $params);
unset($params['user']);
unset($params['user_id']);
@@ -541,21 +564,24 @@ private function outputArrayAsHtml($array, $options = array()) {
/**
* Dumps out an HTML table containing results from a PostgreSQL query.
- * @param array $data PG result data to iterate through.
- * @param array $options Options array. If this has a columns element, it is used to generate a header row and control
- * the output.
+ *
+ * @param array $data
+ * PG result data to iterate through.
+ * @param array $options
+ * Options array. If this has a columns element, it is used to generate a
+ * header row and control the output.
*/
- private function outputResultAsHtml($data, $options) {
+ private function outputResultAsHtml(array $data, array $options) {
echo '';
if (isset($options['columns'])) {
// Ensure href and foriegn key column titles are added if we are including either of them. That's because these
// are dynamically added to the data for each row as we go.
if (!empty($options['preprocess'])) {
if (!empty($options['attachHref']) && !in_array('href', $options['columns'])) {
- $options['columns']['href'] = array();
+ $options['columns']['href'] = [];
}
if (!empty($options['attachFkLink']) && !in_array($options['attachFkLink'][0], $options['columns'])) {
- $options['columns'][$options['attachFkLink'][0]] = array();
+ $options['columns'][$options['attachFkLink'][0]] = [];
}
}
echo '';
From 0cd491a0d1f6d3853f04008363698a85c6fa7f90 Mon Sep 17 00:00:00 2001
From: John van Breda
Date: Tue, 30 Aug 2022 10:52:37 +0100
Subject: [PATCH 5/9] Consistency of details page attribute formatting
Includes option to format newlines and html links embedded in text.
---
application/config/version.php | 4 +-
.../202208291518_format_attr_value.sql | 37 +++++++++++++++++++
.../taxa/taxon_attributes_with_hiddens.xml | 15 ++++----
.../location_data_attributes_with_hiddens.xml | 6 +--
.../record_data_attributes_with_hiddens.xml | 10 ++---
.../sample_data_attributes_with_hiddens.xml | 5 ++-
.../species_attr_description.xml | 24 ++++--------
7 files changed, 64 insertions(+), 37 deletions(-)
create mode 100644 modules/indicia_setup/db/version_8_5_0/202208291518_format_attr_value.sql
diff --git a/application/config/version.php b/application/config/version.php
index 6ee6769bea..681a0a5850 100644
--- a/application/config/version.php
+++ b/application/config/version.php
@@ -29,14 +29,14 @@
*
* @var string
*/
-$config['version'] = '8.4.2';
+$config['version'] = '8.5.0';
/**
* Version release date.
*
* @var string
*/
-$config['release_date'] = '2022-08-24';
+$config['release_date'] = '2022-08-29';
/**
* Link to the code repository downloads page.
diff --git a/modules/indicia_setup/db/version_8_5_0/202208291518_format_attr_value.sql b/modules/indicia_setup/db/version_8_5_0/202208291518_format_attr_value.sql
new file mode 100644
index 0000000000..9ef42e31f4
--- /dev/null
+++ b/modules/indicia_setup/db/version_8_5_0/202208291518_format_attr_value.sql
@@ -0,0 +1,37 @@
+CREATE OR REPLACE FUNCTION get_formatted_attr_text_value(
+ caption text,
+ value text,
+ output_formatting bool
+)
+RETURNS text
+LANGUAGE 'plpgsql'
+IMMUTABLE
+AS
+$BODY$
+--DECLARE
+BEGIN
+ RETURN
+ CASE
+ WHEN substring(caption from (char_length(caption)-5) for 4) = 'link' AND substring(value from 0 for 4) = 'http' THEN
+ '' || value || ''
+ -- Colour value with a secondary colour.
+ WHEN value LIKE '#%;%' THEN ' '
+ || ' '
+ -- Single colour value.
+ WHEN value LIKE '#%' THEN ' '
+ ELSE
+ CASE output_formatting
+ -- Newlines
+ WHEN 't' THEN
+ replace(
+ -- Embedded links in text block formatted if param set.
+ regexp_replace(value, '(http[^\s]*)', '\1'),
+ CHR(13),
+ ' '
+ )
+ ELSE
+ value
+ END
+ END;
+END
+$BODY$;
\ No newline at end of file
diff --git a/reports/library/taxa/taxon_attributes_with_hiddens.xml b/reports/library/taxa/taxon_attributes_with_hiddens.xml
index 0fe4a5c725..d702c200ca 100644
--- a/reports/library/taxa/taxon_attributes_with_hiddens.xml
+++ b/reports/library/taxa/taxon_attributes_with_hiddens.xml
@@ -3,7 +3,7 @@
description="Report used to retrieve custom attributes of an species which are not included in a list of attributes to ignore."
>
- select
+ select
distinct ttl.id, 'Record' as attribute_type, a.system_function,
CASE a.data_type
WHEN 'T'::bpchar THEN 'Text'::bpchar
@@ -14,9 +14,9 @@
WHEN 'D'::bpchar THEN 'Specific Date'::bpchar
WHEN 'V'::bpchar THEN 'Vague Date'::bpchar
ELSE a.data_type
- END AS data_type, a.caption,
+ END AS data_type, a.caption,
CASE a.data_type
- WHEN 'T'::bpchar THEN av.text_value
+ WHEN 'T'::bpchar THEN get_formatted_attr_text_value(a.caption, av.text_value, '#output_formatting#')
WHEN 'L'::bpchar THEN lookup.term::text
WHEN 'I'::bpchar THEN av.int_value::character varying::text
WHEN 'B'::bpchar THEN av.int_value::character varying::text
@@ -24,7 +24,7 @@
WHEN 'D'::bpchar THEN av.date_start_value::character varying::text
WHEN 'V'::bpchar THEN (av.date_start_value::character varying::text || ' - '::text) || av.date_end_value::character varying::text
ELSE NULL::text
- END AS value,
+ END AS value,
CASE a.data_type
WHEN 'T'::bpchar THEN av.text_value
WHEN 'L'::bpchar THEN av.int_value::character varying::text
@@ -39,7 +39,7 @@
join taxa_taxon_lists ttl2 on ttl2.taxon_meaning_id=ttl.taxon_meaning_id and ttl2.deleted=false
join taxa_taxon_list_attribute_values av on av.taxa_taxon_list_id=ttl2.id and av.deleted=false
join taxa_taxon_list_attributes a on a.id=av.taxa_taxon_list_attribute_id and a.deleted=false
- left join cache_termlists_terms lookup on lookup.id=av.int_value
+ left join cache_termlists_terms lookup on lookup.id=av.int_value
WHERE
ttl.id=#taxa_taxon_list_id#
AND ttl.deleted=false
@@ -48,9 +48,10 @@
-
-
+
diff --git a/reports/reports_for_prebuilt_forms/location_details/location_data_attributes_with_hiddens.xml b/reports/reports_for_prebuilt_forms/location_details/location_data_attributes_with_hiddens.xml
index 3eb62da482..f906594a39 100644
--- a/reports/reports_for_prebuilt_forms/location_details/location_data_attributes_with_hiddens.xml
+++ b/reports/reports_for_prebuilt_forms/location_details/location_data_attributes_with_hiddens.xml
@@ -17,10 +17,7 @@
END AS data_type,
CASE '#language#' WHEN '' THEN a.caption ELSE COALESCE(TRIM(BOTH '"' FROM (a.caption_i18n->'#language#')::varchar), a.caption) END AS caption,
STRING_AGG(CASE a.data_type
- WHEN 'T' THEN CASE WHEN substring(a.caption from (char_length(a.caption)-5) for 4) = 'link' AND substring(av.text_value from 0 for 4) = 'http' THEN
- '<a href="' || av.text_value || '">' || av.text_value || '</a>'
- ELSE
- av.text_value END
+ WHEN 'T' THEN get_formatted_attr_text_value(a.caption, av.text_value, '#output_formatting#')
WHEN 'L' THEN lookup.term::text
WHEN 'I' THEN av.int_value::varchar
WHEN 'B' THEN av.int_value::varchar
@@ -65,5 +62,6 @@
datatype='lookup' lookup_values='in:Include,not in:Exclude' />
+
diff --git a/reports/reports_for_prebuilt_forms/record_details_2/record_data_attributes_with_hiddens.xml b/reports/reports_for_prebuilt_forms/record_details_2/record_data_attributes_with_hiddens.xml
index 490fe4c3f4..2698ddde31 100644
--- a/reports/reports_for_prebuilt_forms/record_details_2/record_data_attributes_with_hiddens.xml
+++ b/reports/reports_for_prebuilt_forms/record_details_2/record_data_attributes_with_hiddens.xml
@@ -17,10 +17,7 @@
END AS data_type,
CASE '#language#' WHEN '' THEN a.caption ELSE COALESCE(TRIM(BOTH '"' FROM (a.caption_i18n->'#language#')::varchar), a.caption) END AS caption,
CASE a.data_type
- WHEN 'T' THEN CASE WHEN substring(a.caption from (char_length(a.caption)-5) for 4) = 'link' AND substring(av.text_value from 0 for 4) = 'http' THEN
- '<a href="' || av.text_value || '">' || av.text_value || '</a>'
- ELSE
- av.text_value END
+ WHEN 'T' THEN get_formatted_attr_text_value(a.caption, av.text_value, '#output_formatting#')
WHEN 'L' THEN lookup.term::text
WHEN 'I' THEN av.int_value::varchar
WHEN 'B' THEN av.int_value::varchar
@@ -66,7 +63,7 @@
END AS data_type,
CASE '#language#' WHEN '' THEN a.caption ELSE COALESCE(TRIM(BOTH '"' FROM (a.caption_i18n->'#language#')::varchar), a.caption) END AS caption,
CASE a.data_type
- WHEN 'T' THEN av.text_value
+ WHEN 'T' THEN get_formatted_attr_text_value(a.caption, av.text_value, '#output_formatting#')
WHEN 'L' THEN lookup.term::text
WHEN 'I' THEN coalesce(l.name, av.int_value::varchar)
WHEN 'B' THEN av.int_value::varchar
@@ -115,7 +112,7 @@
END AS data_type,
CASE '#language#' WHEN '' THEN a.caption ELSE COALESCE(TRIM(BOTH '"' FROM (a.caption_i18n->'#language#')::varchar), a.caption) END AS caption,
CASE a.data_type
- WHEN 'T' THEN av.text_value
+ WHEN 'T' THEN get_formatted_attr_text_value(a.caption, av.text_value, '#output_formatting#')
WHEN 'L' THEN lookup.term::text
WHEN 'I' THEN coalesce(l.name, av.int_value::varchar)
WHEN 'B' THEN av.int_value::varchar
@@ -160,5 +157,6 @@
datatype='lookup' lookup_values='in:Include,not in:Exclude' />
+
diff --git a/reports/reports_for_prebuilt_forms/sample_details/sample_data_attributes_with_hiddens.xml b/reports/reports_for_prebuilt_forms/sample_details/sample_data_attributes_with_hiddens.xml
index 1c6bc47537..f66d7cb159 100644
--- a/reports/reports_for_prebuilt_forms/sample_details/sample_data_attributes_with_hiddens.xml
+++ b/reports/reports_for_prebuilt_forms/sample_details/sample_data_attributes_with_hiddens.xml
@@ -18,7 +18,7 @@
END AS data_type,
CASE '#language#' WHEN '' THEN a.caption ELSE COALESCE(TRIM(BOTH '"' FROM (a.caption_i18n->'#language#')::varchar), a.caption) END AS caption,
CASE a.data_type
- WHEN 'T' THEN av.text_value
+ WHEN 'T' THEN get_formatted_attr_text_value(a.caption, av.text_value, '#output_formatting#')
WHEN 'L' THEN lookup.term::text
WHEN 'I' THEN coalesce(l.name, av.int_value::varchar)
WHEN 'B' THEN av.int_value::varchar
@@ -65,7 +65,7 @@
END AS data_type,
CASE '#language#' WHEN '' THEN a.caption ELSE COALESCE(TRIM(BOTH '"' FROM (a.caption_i18n->'#language#')::varchar), a.caption) END AS caption,
CASE a.data_type
- WHEN 'T' THEN av.text_value
+ WHEN 'T' THEN get_formatted_attr_text_value(a.caption, av.text_value, '#output_formatting#')
WHEN 'L' THEN lookup.term::text
WHEN 'I' THEN coalesce(l.name, av.int_value::varchar)
WHEN 'B' THEN av.int_value::varchar
@@ -109,5 +109,6 @@
datatype='lookup' lookup_values='in:Include,not in:Exclude' />
+
diff --git a/reports/reports_for_prebuilt_forms/species_details/species_attr_description.xml b/reports/reports_for_prebuilt_forms/species_details/species_attr_description.xml
index 913a0b06f2..f37469f93c 100644
--- a/reports/reports_for_prebuilt_forms/species_details/species_attr_description.xml
+++ b/reports/reports_for_prebuilt_forms/species_details/species_attr_description.xml
@@ -14,28 +14,19 @@ FROM (
COALESCE(subcat_l.term, subcat.term) as subcategory,
CASE '#include_captions#' WHEN '1' THEN
trim(regexp_replace(regexp_replace(
- CASE '#language#' WHEN '' THEN
- '<b>' || a.caption || '</b>'
- ELSE
- '<b>' || COALESCE(TRIM(BOTH '"' FROM (a.caption_i18n->>'#language#')::varchar), a.caption) || '</b>'
+ CASE '#language#' WHEN '' THEN
+ '<b>' || a.caption || '</b>'
+ ELSE
+ '<b>' || COALESCE(TRIM(BOTH '"' FROM (a.caption_i18n->>'#language#')::varchar), a.caption) || '</b>'
END,
' \(95%\)$', ''), '^' || COALESCE(subcat_l.term, subcat.term), '')) || ': '
- ELSE
- ''
+ ELSE
+ ''
END as caption,
a.caption as raw_caption,
tlttla.weight,
CASE a.data_type
- WHEN 'T'::bpchar THEN
- CASE
- -- colour value with a secondary colour.
- WHEN av.text_value LIKE '#%;%' THEN '<span style="width: 30px; height: 15px; display: inline-block; background-color: ' || split_part(av.text_value, ';', 1) || '"> </span>'
- || '<span style="width: 30px; height: 15px; display: inline-block; background-color: ' || split_part(av.text_value, ';', 2) || '"> </span>'
- -- single colour value.
- WHEN av.text_value LIKE '#%' THEN '<span style="width: 30px; height: 15px; display: inline-block; background-color: ' || av.text_value || '"> </span>'
- -- any other value.
- ELSE av.text_value
- END
+ WHEN 'T' THEN get_formatted_attr_text_value(a.caption, av.text_value, '#output_formatting#')
WHEN 'L'::bpchar THEN COALESCE(t_l.term::text, t.term::text)
WHEN 'I'::bpchar THEN
CASE
@@ -106,6 +97,7 @@ FROM (
+
From 55f8191d5d747af6111ba0cc0eee6b9bb6016990 Mon Sep 17 00:00:00 2001
From: John van Breda
Date: Thu, 8 Sep 2022 10:58:14 +0100
Subject: [PATCH 6/9] Linting
---
application/libraries/XMLReportReader.php | 203 +++++++++++-----------
1 file changed, 106 insertions(+), 97 deletions(-)
diff --git a/application/libraries/XMLReportReader.php b/application/libraries/XMLReportReader.php
index 7623a58265..81b89ccfe2 100644
--- a/application/libraries/XMLReportReader.php
+++ b/application/libraries/XMLReportReader.php
@@ -848,7 +848,7 @@ public function describeReport($descLevel) {
/**
*/
public function getAttributeDefns() {
- return $this->attributes;
+ return $this->attributes;
}
public function getVagueDateProcessing() {
@@ -1005,7 +1005,7 @@ private function mergeParam($name, $reader = NULL) {
'population_call',
'linked_to',
'linked_filter_field',
- 'order_by'
+ 'order_by',
]);
if ($this->params[$name]['datatype'] === 'lookup') {
@@ -1030,21 +1030,21 @@ private function mergeParam($name, $reader = NULL) {
if (!isset($this->params[$name]['joins'])) {
$this->params[$name]['joins'] = [];
}
- $this->params[$name]['joins'][] = array(
+ $this->params[$name]['joins'][] = [
'value' => $reader->getAttribute('value'),
'operator' => $reader->getAttribute('operator'),
'sql' => $reader->readString(),
- );
+ ];
}
if ($reader->nodeType == XMLREADER::ELEMENT && $reader->name === 'where') {
if (!isset($this->params[$name]['wheres'])) {
$this->params[$name]['wheres'] = [];
}
- $this->params[$name]['wheres'][] = array(
+ $this->params[$name]['wheres'][] = [
'value' => $reader->getAttribute('value'),
'operator' => $reader->getAttribute('operator'),
'sql' => $reader->readString(),
- );
+ ];
}
}
}
@@ -1238,8 +1238,7 @@ private function mergeXmlColumn($reader) {
private function mergeColumn($name, $display = '', $style = '', $feature_style='', $class='', $visible='', $img='',
$orderby='', $mappable='', $autodef=TRUE) {
- if (array_key_exists($name, $this->columns))
- {
+ if (array_key_exists($name, $this->columns)) {
if ($display != '') $this->columns[$name]['display'] = $display;
if ($style != '') $this->columns[$name]['style'] = $style;
if ($feature_style != '') $this->columns[$name]['feature_style'] = $feature_style;
@@ -1256,17 +1255,17 @@ private function mergeColumn($name, $display = '', $style = '', $feature_style='
}
else
{
- $this->columns[$name] = array(
- 'display' => $display,
- 'style' => $style,
- 'feature_style' => $feature_style,
- 'class' => $class,
- 'visible' => $visible == '' ? 'true' : $visible,
- 'img' => $img == '' ? 'false' : $img,
- 'orderby' => $orderby,
- 'mappable' => empty($mappable) ? 'false' : $mappable,
- 'autodef' => $autodef,
- );
+ $this->columns[$name] = [
+ 'display' => $display,
+ 'style' => $style,
+ 'feature_style' => $feature_style,
+ 'class' => $class,
+ 'visible' => $visible == '' ? 'true' : $visible,
+ 'img' => $img == '' ? 'false' : $img,
+ 'orderby' => $orderby,
+ 'mappable' => empty($mappable) ? 'false' : $mappable,
+ 'autodef' => $autodef,
+ ];
}
}
@@ -1275,51 +1274,55 @@ private function setTable($tablename, $where) {
$this->tableIndex = 0;
$this->nextTableIndex = 1;
$this->tables[$this->tableIndex] = [
- 'tablename' => $tablename,
- 'parent' => -1,
- 'parentKey' => '',
- 'tableKey' => '',
- 'join' => '',
- 'attributes' => '',
- 'where' => $where,
- 'columns' => []
+ 'tablename' => $tablename,
+ 'parent' => -1,
+ 'parentKey' => '',
+ 'tableKey' => '',
+ 'join' => '',
+ 'attributes' => '',
+ 'where' => $where,
+ 'columns' => [],
];
}
private function setSubTable($tablename, $parentKey, $tableKey, $join, $where) {
- if($tableKey == ''){
- if($parentKey == 'id'){
- $tableKey = 'lt'.$this->nextTableIndex.".".(inflector::singular($this->tables[$this->tableIndex]['tablename'])).'_id';
+ if ($tableKey == '') {
+ if ($parentKey == 'id') {
+ $tableKey = 'lt' . $this->nextTableIndex . "." . (inflector::singular($this->tables[$this->tableIndex]['tablename'])) . '_id';
} else {
- $tableKey = 'lt'.$this->nextTableIndex.'.id';
+ $tableKey = 'lt' . $this->nextTableIndex . '.id';
}
} else {
- $tableKey = 'lt'.$this->nextTableIndex.".".$tableKey;
+ $tableKey = 'lt' . $this->nextTableIndex . "." . $tableKey;
+ }
+ if ($parentKey == '') {
+ $parentKey = 'lt' . $this->tableIndex . "." . (inflector::singular($tablename)) . '_id';
}
- if($parentKey == ''){
- $parentKey = 'lt'.$this->tableIndex.".".(inflector::singular($tablename)).'_id';
- } else { // force the link as this table has foreign key to parent table, standard naming convention.
- $parentKey = 'lt'.$this->tableIndex.".".$parentKey;
+ else {
+ // Force the link as this table has foreign key to parent table, standard
+ // naming convention.
+ $parentKey = 'lt' . $this->tableIndex . '.' . $parentKey;
}
- $this->tables[$this->nextTableIndex] = array(
- 'tablename' => $tablename,
- 'parent' => $this->tableIndex,
- 'parentKey' => $parentKey,
- 'tableKey' => $tableKey,
- 'join' => $join,
- 'attributes' => '',
- 'where' => $where,
- 'columns' => []);
- $this->tableIndex=$this->nextTableIndex;
+ $this->tables[$this->nextTableIndex] = [
+ 'tablename' => $tablename,
+ 'parent' => $this->tableIndex,
+ 'parentKey' => $parentKey,
+ 'tableKey' => $tableKey,
+ 'join' => $join,
+ 'attributes' => '',
+ 'where' => $where,
+ 'columns' => [],
+ ];
+ $this->tableIndex = $this->nextTableIndex;
$this->nextTableIndex++;
}
- private function mergeTabColumn($name, $func = '', $display = '', $style = '', $feature_style = '', $class='', $visible='', $autodef=FALSE) {
+ private function mergeTabColumn($name, $func = '', $display = '', $style = '', $feature_style = '', $class = '', $visible = '', $autodef = FALSE) {
$found = FALSE;
- for($r = 0; $r < count($this->tables[$this->tableIndex]['columns']); $r++){
- if($this->tables[$this->tableIndex]['columns'][$r]['name'] == $name) {
+ for ($r = 0; $r < count($this->tables[$this->tableIndex]['columns']); $r++){
+ if ($this->tables[$this->tableIndex]['columns'][$r]['name'] == $name) {
$found = TRUE;
- if($func != '') {
+ if ($func != '') {
$this->tables[$this->tableIndex]['columns'][$r]['func'] = $func;
}
}
@@ -1329,7 +1332,7 @@ private function mergeTabColumn($name, $func = '', $display = '', $style = '', $
'name' => $name,
'func' => $func,
];
- if($display == '') {
+ if ($display == '') {
$display = $this->tables[$this->tableIndex]['tablename']." ".$name;
}
}
@@ -1371,7 +1374,7 @@ private function setAttributes($where, $separator, $hideVagueDateFields, $meanin
$thisDefn->id = 'id'; // id is the name of the column in the subquery holding the attribute id.
$thisDefn->separator = $separator;
$thisDefn->hideVagueDateFields = $hideVagueDateFields;
- $thisDefn->columnPrefix = 'attr_' . $this->tableIndex.'_';
+ $thisDefn->columnPrefix = 'attr_' . $this->tableIndex . '_';
// Folowing is used the query builder only.
$thisDefn->parentTableIndex = $this->tableIndex;
$thisDefn->where = $where;
@@ -1392,14 +1395,13 @@ private function setDownload($mode) {
* matching from. Commas that are part of nested selects or function calls are ignored
* provided they are enclosed in brackets.
*/
- private function inferFromQuery()
- {
- // Find the columns we're searching for - nested between a SELECT and a FROM.
- // To ensure we can detect the words FROM, SELECT and AS, use a regex to wrap
- // spaces around them, then can do a regular string search
- $this->query=preg_replace("/\b(select)\b/i", ' select ', $this->query);
- $this->query=preg_replace("/\b(from)\b/i", ' from ', $this->query);
- $this->query=preg_replace("/\b(as)\b/i", ' as ', $this->query);
+ private function inferFromQuery() {
+ // Find the columns we're searching for - nested between a SELECT and a
+ // FROM. To ensure we can detect the words FROM, SELECT and AS, use a regex
+ // to wrap spaces around them, then can do a regular string search.
+ $this->query = preg_replace("/\b(select)\b/i", ' select ', $this->query);
+ $this->query = preg_replace("/\b(from)\b/i", ' from ', $this->query);
+ $this->query = preg_replace("/\b(as)\b/i", ' as ', $this->query);
$i0 = strpos($this->query, ' select ') + 7;
$nesting = 1;
$offset = $i0;
@@ -1407,13 +1409,13 @@ private function inferFromQuery()
$nextSelect = strpos($this->query, ' select ', $offset);
$nextFrom = strpos($this->query, ' from ', $offset);
if ($nextSelect !== FALSE && $nextSelect < $nextFrom) {
- //found start of sub-query
+ // Found start of sub-query.
$nesting++;
$offset = $nextSelect + 7;
} else {
$nesting--;
if ($nesting != 0) {
- //found end of sub-query
+ // Found end of sub-query.
$offset = $nextFrom + 5;
}
}
@@ -1425,36 +1427,36 @@ private function inferFromQuery()
$colString = str_replace('#fields#', '', substr($this->query, $i0, $i1));
// Now divide up the list of columns, which are comma separated, but ignore
- // commas nested in brackets
+ // commas nested in brackets.
$colStart = 0;
- $nextComma = strpos($colString, ',', $colStart);
- while ($nextComma !== FALSE)
- {//loop through columns
- $nextOpen = strpos($colString, '(', $colStart);
- while ($nextOpen !== FALSE && $nextComma !==FALSE && $nextOpen < $nextComma)
- { //skipping commas in brackets
+ $nextComma = strpos($colString, ',', $colStart);
+ while ($nextComma !== FALSE) {
+ // Loop through columns.
+ $nextOpen = strpos($colString, '(', $colStart);
+ while ($nextOpen !== FALSE && $nextComma !== FALSE && $nextOpen < $nextComma) {
+ // Skipping commas in brackets.
$offset = $this->strposclose($colString, $nextOpen) + 1;
- $nextComma = strpos($colString, ',', $offset);
- $nextOpen = strpos($colString, '(', $offset);
+ $nextComma = strpos($colString, ',', $offset);
+ $nextOpen = strpos($colString, '(', $offset);
}
if ($nextComma !== FALSE) {
- //extract column and move on to next
+ // Extract column and move on to next.
$cols[] = substr($colString, $colStart, ($nextComma - $colStart));
$colStart = $nextComma + 1;
- $nextComma = strpos($colString, ',', $colStart);
- }
+ $nextComma = strpos($colString, ',', $colStart);
+ }
}
- //extract final column
+ // Extract final column.
$cols[] = substr($colString, $colStart);
- // We have cols, which may either be of the form 'x', 'table.x' or 'x as y'. Either way the column name is the part after the last
- // space and full stop.
- foreach ($cols as $col)
- {
- // break down by spaces
- $b = explode(' ' , trim($col));
- // break down the part after the last space, by
- $c = explode('.' , array_pop($b));
+ // We have cols, which may either be of the form 'x', 'table.x' or 'x as
+ // y'. Either way the column name is the part after the last space and full
+ // stop.
+ foreach ($cols as $col) {
+ // Break down by spaces.
+ $b = explode(' ', trim($col));
+ // Break down the part after the last space.
+ $c = explode('.', array_pop($b));
$d = array_pop($c);
$this->mergeColumn(trim($d));
}
@@ -1462,34 +1464,41 @@ private function inferFromQuery()
// Okay, now we need to find parameters, which we do with regex.
preg_match_all('/#([a-z0-9_]+)#%/i', $this->query, $matches);
// Here is why I remember (yet again) why I hate PHP...
- foreach ($matches[1] as $param)
- {
+ foreach ($matches[1] as $param) {
$this->mergeParam($param);
}
}
/**
- * Returns the numeric position of the closing bracket matching the opening bracket
- * @param $haystack The string to search
- * @param $open The numeric position of the opening bracket
- * @return The numeric position of the closing bracket or FALSE if not present
+ * Returns numeric pos of the closing bracket matching an opening bracket.
+ *
+ * @param string $haystack
+ * The string to search.
+ * @param int $open
+ * The numeric position of the opening bracket.
+ *
+ * @return int
+ * The numeric position of the closing bracket or FALSE if not present.
*/
private function strposclose($haystack, $open) {
$nesting = 1;
$offset = $open + 1;
do {
- $nextOpen = strpos($haystack, '(', $offset);
- $nextClose = strpos($haystack, ')', $offset);
- if ($nextClose === FALSE) return FALSE;
+ $nextOpen = strpos($haystack, '(', $offset);
+ $nextClose = strpos($haystack, ')', $offset);
+ if ($nextClose === FALSE) {
+ return FALSE;
+ }
if ($nextOpen !== FALSE and $nextOpen < $nextClose) {
$nesting++;
$offset = $nextOpen + 1;
- } else {
+ }
+ else {
$nesting--;
$offset = $nextClose + 1;
}
- }
- while ($nesting > 0);
- return $offset -1;
+ } while ($nesting > 0);
+ return $offset - 1;
}
-}
\ No newline at end of file
+
+}
From 9d02873d9581af5eda073cd7145d463f823e3b45 Mon Sep 17 00:00:00 2001
From: John van Breda
Date: Fri, 9 Sep 2022 09:08:37 +0100
Subject: [PATCH 7/9] Version up for code already in develop due to hotfeature
---
application/config/version.php | 2 +-
.../202208291518_format_attr_value.sql | 0
2 files changed, 1 insertion(+), 1 deletion(-)
rename modules/indicia_setup/db/{version_8_5_0 => version_8_6_0}/202208291518_format_attr_value.sql (100%)
diff --git a/application/config/version.php b/application/config/version.php
index a95e5ecb50..1e4be2c762 100644
--- a/application/config/version.php
+++ b/application/config/version.php
@@ -29,7 +29,7 @@
*
* @var string
*/
-$config['version'] = '8.5.0';
+$config['version'] = '8.6.0';
/**
* Version release date.
diff --git a/modules/indicia_setup/db/version_8_5_0/202208291518_format_attr_value.sql b/modules/indicia_setup/db/version_8_6_0/202208291518_format_attr_value.sql
similarity index 100%
rename from modules/indicia_setup/db/version_8_5_0/202208291518_format_attr_value.sql
rename to modules/indicia_setup/db/version_8_6_0/202208291518_format_attr_value.sql
From 4f227aef77a7c99e9f0588eb9495dc5a0e42221c Mon Sep 17 00:00:00 2001
From: John van Breda
Date: Fri, 9 Sep 2022 11:31:36 +0100
Subject: [PATCH 8/9] Changelog updated
---
CHANGELOG.md | 6 ++++++
1 file changed, 6 insertions(+)
diff --git a/CHANGELOG.md b/CHANGELOG.md
index bb5da80db8..5f7b523735 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,3 +1,9 @@
+# Version 8.5.0
+*2022-09-09*
+
+* Adds a new standard filter parameter for filtering occurrences by sample ID (smp_id).
+* Adds reports required to support a new recording_system_links Drupal module.
+
# Version 8.4.0
*2022-08-10*
From 5d74ca01cb563af7dabeaf77fc06f30df7f0a62b Mon Sep 17 00:00:00 2001
From: John van Breda
Date: Fri, 9 Sep 2022 12:15:49 +0100
Subject: [PATCH 9/9] CHANGELOG updated
---
CHANGELOG.md | 7 +++++++
1 file changed, 7 insertions(+)
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 5f7b523735..15354d1dee 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,3 +1,10 @@
+# Version 8.6.0
+*2022-09-09"
+
+* Support for new output_formatting option in reports for details pages (occurrences, samples,
+ locations) with auto-formatting of hyperlinks for text attribute data.
+* Improvements to the REST API's auto-generated documentation.
+
# Version 8.5.0
*2022-09-09*
|
---|