diff --git a/CHANGELOG.md b/CHANGELOG.md
index 5a5b72c397..b59789795e 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -5,6 +5,7 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/).
## Unreleased
+- Fix #831: Check if longitude and lagitude match the WGS84 format for sample attributes
- Feat #1867: Update the gitlab static application security testing (SAST) job using the Semgrep-based analyzer
- Fix #2066: Max length for attribute value set to 1000 in file admin form
- Feat #1968: Add curators manual for operating tools on bastion server
diff --git a/data/dev/attribute.csv b/data/dev/attribute.csv
index 0bdc680c7c..5be2203dbc 100644
--- a/data/dev/attribute.csv
+++ b/data/dev/attribute.csv
@@ -18,6 +18,8 @@ id,attribute_name,definition,model,structured_comment_name,value_syntax,allowed_
347,last_modified,the date the file was last modified,modified,last_modified,date,"",1,"",""
356,Description,"description of the sample (may include many attributes as human readable text, but these should also be added as independent attribute:value pairs).","",description,text,"",1,"",""
376,estimated genome size,"An estimate of the size of the genome of the species being studied, in basepairs (Gb, Mb or Kb)","",est_genome_size,text,"",1,"",""
+391,geographic location (latitude),"The geographical latitudinal origin of the sample, the value should be reported in decimal degrees and in WGS84 system","",latitude,number,"","","",""
+392,geographic location (longitude),"The geographical longitudinal origin of the sample, the value should be reported in decimal degrees and in WGS84 system","",longitude,number,"","","",""
448,alternative accession-biosample,"","",alt_acc_biosample,"","","","",""
455,keyword,"","",keywords,"","","","",""
472,camera parameters,"","",camera_parameters,text,"",m,"",""
diff --git a/protected/controllers/AdminSampleController.php b/protected/controllers/AdminSampleController.php
index 7c26cc263d..6d187ff7ea 100644
--- a/protected/controllers/AdminSampleController.php
+++ b/protected/controllers/AdminSampleController.php
@@ -23,7 +23,7 @@ public function accessRules()
{
return array(
array('allow', // admin only
- 'actions'=>array('admin','delete','index','view','create','update'),
+ 'actions'=>array('admin','delete','index','view','create','update', 'checkAttribute'),
'roles'=>array('admin'),
),
array('allow', 'actions' => array('create1', 'choose'), 'users' => array('@')),
@@ -193,50 +193,43 @@ public function actionChoose() {
public function actionUpdate($id)
{
$model = $this->loadModel($id);
- //$old_code= $model->code;
- // Uncomment the following line if AJAX validation is needed
- // $this->performAjaxValidation($model);
- if (isset($_POST['Sample'])) {
- $model->attributes = $_POST['Sample'];
- $model->name = $_POST['Sample']['name'];
-
- if (strpos($_POST['Sample']['species_id'], ":") !== false) {
- $array = explode(":", $_POST['Sample']['species_id']);
- $tax_id = $array[0];
- if (!empty($tax_id)) {
- $species = $this->findSpeciesRecord($tax_id, $model);
- $this->updateSampleAttributes($model);
- if (!$model->hasErrors()) {
- $this->redirect(array('view', 'id' => $model->id));
- }
- } else {
- $model->addError('error', 'Taxon ID is empty!');
- }
- } else {
+ if ($sampleAttribute = Yii::$app->request->post('Sample')) {
+ $model->name = $sampleAttribute['name'];
+
+ if (!strpos($sampleAttribute['species_id'], ':')) {
$model->addError('error', 'The input format is wrong, should be tax_id:common_name');
}
- }
- $species = Species::model()->findByPk($model->species_id);
+ $array = explode(':', $sampleAttribute['species_id']);
+ $tax_id = $array[0];
- $model->species_id = $species->tax_id . ":";
- $has_common_name = false;
- if ($species->common_name != null) {
- $has_common_name = true;
- $model->species_id .= $species->common_name;
- }
+ if (!$tax_id) {
+ $model->addError('error', 'Taxon ID is empty!');
+ }
+
+ if (!$this->findSpeciesRecord($tax_id, $model)) {
+ $model->addError('error', 'The species does not exist');
+ }
+
+ if ($model->save()) {
+ $this->updateSampleAttributes($model);
+ }
- if ($species->scientific_name != null) {
- if ($has_common_name) {
- $model->species_id .= ",";
+ if (!$model->hasErrors()) {
+ $this->redirect(array('view', 'id' => $model->id));
}
- $model->species_id .= $species->scientific_name;
}
- $this->render('update', array(
- 'model' => $model,
- 'species' => $species,
- ));
+
+ $species = Species::model()->findByPk($model->species_id);
+
+ $model->species_id = sprintf('%s: %s', $species->tax_id, $species->common_name ?: '');
+ $model->species_id .= sprintf('%s%s', $species->common_name ? ', ' : '', $species->scientific_name ?: '');
+
+ $this->render('update', array(
+ 'model' => $model,
+ 'species' => $species,
+ ));
}
/**
@@ -315,6 +308,47 @@ protected function performAjaxValidation($model)
}
}
+ public function actionCheckAttribute()
+ {
+ if (!Yii::app()->request->isAjaxRequest) {
+ throw new CHttpException(400,'Invalid request. An Error occurred');
+ }
+
+ $errorMessage = [];
+ $attributesList = $_POST['attr'];
+
+ foreach (explode('",', $attributesList) as $attributes) {
+ $attributes = str_replace('"', '', $attributes);
+ $attributeData = explode('=', $attributes);
+ if (count($attributeData) === 2) {
+ $attributeData[0] = trim($attributeData[0]);
+ if ($attributeData[0] !== 'longitude' && $attributeData[0] !== 'latitude') {
+ continue;
+ }
+
+ $errorMessage = $this->checkWrongLatLongAttribute($attributeData[0], $attributeData[1]);
+ }
+ }
+
+ echo CJSON::encode(['messages' => $errorMessage]);
+ Yii::app()->end();
+ }
+
+ private function checkWrongLatLongAttribute(string $attribute, string $attributeValue): array
+ {
+ $errorMessage = [];
+ if (preg_match('/^[^0-9]*$/', $attributeValue)) {
+ $errorMessage[] = sprintf('Attribute value for %s doesn\'t match WGS84 decimal format.
+ For geographic location (country, sea, region) use another attribute name', $attribute);
+ } else if ($attributeData[0] === 'latitude' && !preg_match('/^[-+]?(?:90(?:\.0+)?|[1-8]?\d(?:\.\d+)?)$/', $attributeValue)) {
+ $errorMessage[] = sprintf('Attribute value for %s doesn\'t match WGS84 decimal format', $attribute);
+ } else if ($attributeData[0] === 'longitude' && !preg_match('/^[-+]?(?:180(?:\.0+)?|1[0-7]\d(?:\.\d+)?|\d{1,2}(?:\.\d+)?)$/', $attributeValue)) {
+ $errorMessage[] = sprintf('Attribute value for %s doesn\'t match WGS84 decimal format', $attribute);
+ }
+
+ return $errorMessage;
+ }
+
/**
* Upate sample attribute
*
@@ -332,20 +366,28 @@ private function updateSampleAttributes($model)
$sampleAttribute->sample_id = $model->id;
$attributes = str_replace('"', '', $attributes);
$attributeData = explode('=', $attributes);
- if (count($attributeData) == 2) {
+ if (count($attributeData) === 2) {
// Get attribute model
$attribute = Attributes::model()->findByAttributes(array('structured_comment_name' => trim($attributeData[0])));
if (!$attribute) {
$model->addError('error', 'Attribute name for the input ' . $attributeData[0] . "=" . $attributeData[1] . ' is not valid - please select a valid attribute name!');
- } else {
- // Let's save the new sample attribute
- $sampleAttribute->value = trim($attributeData[1]);
- $sampleAttribute->attribute_id = $attribute->id;
- if (!$sampleAttribute->save(true)) {
- foreach ($sampleAttribute->getErrors() as $errors) {
- foreach ($errors as $errorMessage) {
- $model->addError('error', $errorMessage);
- }
+
+ continue;
+ }
+
+ if ($attributeData[0] === 'longitude' || $attributeData[0] === 'latitude') {
+ if ($this->checkWrongLatLongAttribute($attributeData[0], $attributeData[1])) {
+ continue;
+ }
+ }
+
+ // Let's save the new sample attribute
+ $sampleAttribute->value = trim($attributeData[1]);
+ $sampleAttribute->attribute_id = $attribute->id;
+ if (!$sampleAttribute->save()) {
+ foreach ($sampleAttribute->getErrors() as $errors) {
+ foreach ($errors as $errorMessage) {
+ $model->addError('error', $errorMessage);
}
}
}
diff --git a/protected/views/adminSample/_form.php b/protected/views/adminSample/_form.php
index 0f608b9660..ffc181921f 100644
--- a/protected/views/adminSample/_form.php
+++ b/protected/views/adminSample/_form.php
@@ -9,11 +9,13 @@
Fields with * are required.
hasErrors()) : ?>
-
+
errorSummary($model); ?>
+
An error occurred
+
+
endWidget(); ?>
-
\ No newline at end of file
+
+
diff --git a/tests/acceptance/AdminSample.feature b/tests/acceptance/AdminSample.feature
index f5743fa1be..d56381035c 100644
--- a/tests/acceptance/AdminSample.feature
+++ b/tests/acceptance/AdminSample.feature
@@ -21,6 +21,9 @@ Feature: admin page for samples
When I fill in the field of "name" "Sample[species_id]" with ":Foxtail millet"
And I press the button "Save"
And I wait "1" seconds
+ Then I should see "Are you sure you want to continue?"
+ And I press the button "Confirm"
+ And I wait "1" seconds
Then I should see "Please fix the following input errors:"
And I should see "Taxon ID is empty!"
@@ -31,6 +34,8 @@ Feature: admin page for samples
When I fill in the field of "name" "Sample[attributesList]" with "source_mat_id=\"David Lambert & BGI\",est_genome_size=\"1.32\",alternative_names=\"PYGAD\",animal=\"tiger\""
And I press the button "Save"
And I wait "1" seconds
+ And I press the button "Confirm"
+ And I wait "1" seconds
Then I should see "Please fix the following input errors:"
And I should see "Attribute name for the input animal=\tiger\ is not valid - please select a valid attribute name!"
And I should see "David Lambert"
@@ -43,6 +48,8 @@ Feature: admin page for samples
And I should see "lat_lon"
And I press the button "Save"
And I wait "1" seconds
+ And I press the button "Confirm"
+ And I wait "1" seconds
And I should see "David Lambert"
And I should see "1.32"
And I should see "PYGAD"
@@ -54,6 +61,8 @@ Feature: admin page for samples
When I fill in the field of "name" "Sample[species_id]" with "4555=Foxtail millet"
And I press the button "Save"
And I wait "1" seconds
+ And I press the button "Confirm"
+ And I wait "1" seconds
Then I should see "Please fix the following input errors:"
And I should see "The input format is wrong, should be tax_id:common_name"
@@ -64,6 +73,8 @@ Feature: admin page for samples
When I fill in the field of "name" "Sample[attributesList]" with "animal=\"tiger\",plant=\"rose\""
And I press the button "Save"
And I wait "1" seconds
+ And I press the button "Confirm"
+ And I wait "1" seconds
Then I should see "Please fix the following input errors:"
And I should see "Attribute name for the input animal=\tiger\ is not valid - please select a valid attribute name!"
And I should see "Attribute name for the input plant=\rose\ is not valid - please select a valid attribute name!"
@@ -75,6 +86,8 @@ Feature: admin page for samples
When I fill in the field of "name" "Sample[species_id]" with "Human"
And I press the button "Create"
And I wait "1" seconds
+ And I press the button "Confirm"
+ And I wait "1" seconds
Then I should see "Please fix the following input errors:"
And I should see "Taxon ID Human is not numeric!"
@@ -85,6 +98,8 @@ Feature: admin page for samples
When I fill in the field of "name" "Sample[species_id]" with "789123"
And I press the button "Create"
And I wait "1" seconds
+ And I press the button "Confirm"
+ And I wait "1" seconds
Then I should see "Please fix the following input errors:"
And I should see "Taxon ID 789123 is not found!"
@@ -96,9 +111,102 @@ Feature: admin page for samples
And I fill in the field of "name" "Sample[attributesList]" with "animal=\"tiger\""
And I press the button "Create"
And I wait "1" seconds
+ And I press the button "Confirm"
+ And I wait "1" seconds
Then I should see "Please fix the following input errors:"
And I should see "Attribute name for the input animal=\tiger\ is not valid - please select a valid attribute name!"
+ Scenario: display 1 warning message when create with wrong latitude beyond 90
+ Given I am on "/adminSample/create"
+ And I should see "Create"
+ When I fill in the field of "name" "Sample[species_id]" with "87676:Eucalyptus pauciflora"
+ And I fill in the field of "name" "Sample[attributesList]" with "latitude=\"95.1234\""
+ And I press the button "Create"
+ And I wait "1" seconds
+ Then I should see "Are you sure you want to continue?"
+ And I should see "Attribute value for latitude doesn't match WGS84 decimal format"
+ And I press the button "Confirm"
+ And I wait "1" seconds
+ Then I should not see "Please fix the following input errors:"
+
+ Scenario: display 1 warning message when create with wrong latitude below -90
+ Given I am on "/adminSample/create"
+ And I should see "Create"
+ When I fill in the field of "name" "Sample[species_id]" with "87676:Eucalyptus pauciflora"
+ And I fill in the field of "name" "Sample[attributesList]" with "latitude=\"-95.1234\""
+ And I press the button "Create"
+ And I wait "1" seconds
+ Then I should see "Are you sure you want to continue?"
+ And I should see "Attribute value for latitude doesn't match WGS84 decimal format"
+ And I press the button "Confirm"
+ And I wait "1" seconds
+ Then I should not see "Please fix the following input errors:"
+
+ Scenario: display 1 warning message when create with wrong longitude beyond 180
+ Given I am on "/adminSample/create"
+ And I should see "Create"
+ When I fill in the field of "name" "Sample[species_id]" with "87676:Eucalyptus pauciflora"
+ And I fill in the field of "name" "Sample[attributesList]" with "longitude=\"200.1234\""
+ And I press the button "Create"
+ And I wait "1" seconds
+ Then I should see "Are you sure you want to continue?"
+ And I should see "Attribute value for longitude doesn't match WGS84 decimal format"
+ And I press the button "Confirm"
+ And I wait "1" seconds
+ Then I should not see "Please fix the following input errors:"
+
+ Scenario: display 1 warning message when create with wrong longitude below -180
+ Given I am on "/adminSample/create"
+ And I should see "Create"
+ When I fill in the field of "name" "Sample[species_id]" with "87676:Eucalyptus pauciflora"
+ And I fill in the field of "name" "Sample[attributesList]" with "longitude=\"-200.1234\""
+ And I press the button "Create"
+ And I wait "1" seconds
+ Then I should see "Attribute value for longitude doesn't match WGS84 decimal format"
+ And I should see "Are you sure you want to continue?"
+ And I press the button "Confirm"
+ And I wait "1" seconds
+ Then I should not see "Please fix the following input errors:"
+
+ Scenario: display 1 warning message when create with incorrect formatting
+ Given I am on "/adminSample/create"
+ And I should see "Create"
+ When I fill in the field of "name" "Sample[species_id]" with "87676:Eucalyptus pauciflora"
+ And I fill in the field of "name" "Sample[attributesList]" with "longitude=\"123.456.789\""
+ And I press the button "Create"
+ And I wait "1" seconds
+ Then I should see "Are you sure you want to continue?"
+ And I should see "Attribute value for longitude doesn't match WGS84 decimal format"
+ And I press the button "Confirm"
+ And I wait "1" seconds
+ Then I should not see "Please fix the following input errors:"
+
+ Scenario: display 1 extra message when create with extra symbol
+ Given I am on "/adminSample/create"
+ And I should see "Create"
+ When I fill in the field of "name" "Sample[species_id]" with "87676:Eucalyptus pauciflora"
+ And I fill in the field of "name" "Sample[attributesList]" with "longitude=\"123.4567°\""
+ And I press the button "Create"
+ And I wait "1" seconds
+ Then I should see "Are you sure you want to continue?"
+ And I should see "Attribute value for longitude doesn't match WGS84 decimal format"
+ And I press the button "Confirm"
+ And I wait "1" seconds
+ Then I should not see "Please fix the following input errors:"
+
+ Scenario: display 1 warning message when create with region for lat_lon
+ Given I am on "/adminSample/create"
+ And I should see "Create"
+ When I fill in the field of "name" "Sample[species_id]" with "87676:Eucalyptus pauciflora"
+ And I fill in the field of "name" "Sample[attributesList]" with "latitude=something"
+ And I press the button "Create"
+ And I wait "1" seconds
+ Then I should see "Are you sure you want to continue?"
+ And I should see "Attribute value for latitude doesn't match WGS84 decimal format. For geographic location (country, sea, region) use another attribute name"
+ And I press the button "Confirm"
+ And I wait "1" seconds
+ Then I should not see "Please fix the following input errors:"
+
@ok
Scenario: display 2 input error messages when create
Given I am on "/adminSample/create"
@@ -107,6 +215,8 @@ Feature: admin page for samples
And I fill in the field of "name" "Sample[attributesList]" with "animal=\"tiger\",plant=\"rose\""
And I press the button "Create"
And I wait "1" seconds
+ And I press the button "Confirm"
+ And I wait "1" seconds
Then I should see "Please fix the following input errors:"
And I should see "Attribute name for the input animal=\tiger\ is not valid - please select a valid attribute name!"
And I should see "Attribute name for the input plant=\rose\ is not valid - please select a valid attribute name!"
@@ -119,6 +229,8 @@ Feature: admin page for samples
And I fill in the field of "name" "Sample[attributesList]" with "sex=\"male\",alternative_names=\"Alternative name here\""
And I press the button "Create"
And I wait "1" seconds
+ And I press the button "Confirm"
+ And I wait "1" seconds
Then I should see "View Sample #451"
And I should see "male"
And I should see "Alternative name here"