From 653665f8eb7f49d4970abdefabd5d0602bec6719 Mon Sep 17 00:00:00 2001 From: Allison Guilhem Date: Tue, 10 Sep 2024 15:25:00 +1000 Subject: [PATCH] fix: sample attribute lat lon regex and migration --- CHANGELOG.md | 1 + data/dev/attribute.csv | 2 + .../controllers/AdminSampleController.php | 136 ++++++++++++------ protected/views/adminSample/_form.php | 84 ++++++++++- tests/acceptance/AdminSample.feature | 112 +++++++++++++++ 5 files changed, 285 insertions(+), 50 deletions(-) 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); ?>
+ +
labelEx($model, 'species_id', array('class' => 'control-label')); ?> Cancel - isNewRecord ? 'Create' : 'Save', array('class' => 'btn background-btn')); ?> + +
+ 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"