From da8e381d31fba7056af2f7fc3b91c7f2bb54416c Mon Sep 17 00:00:00 2001 From: Stuart Owen Date: Tue, 24 Sep 2024 11:08:31 +0100 Subject: [PATCH] handling validation errors #1981 --- app/controllers/investigations_controller.rb | 18 +- ...ek-fair-data-station-invalid-test-case.ttl | 353 ++++++++++++++++++ .../investigations_controller_test.rb | 27 ++ 3 files changed, 394 insertions(+), 4 deletions(-) create mode 100755 test/fixtures/files/fairdatastation/seek-fair-data-station-invalid-test-case.ttl diff --git a/app/controllers/investigations_controller.rb b/app/controllers/investigations_controller.rb index 3e2e7226cf..099eb4db37 100644 --- a/app/controllers/investigations_controller.rb +++ b/app/controllers/investigations_controller.rb @@ -38,20 +38,30 @@ def new_object_based_on_existing_one def submit_fairdata_station path = params[:datastation_data].path datastation_inv = Seek::FairDataStation::Reader.new.parse_graph(path).first + error = false if datastation_inv.external_id != @investigation.external_identifier flash[:error] = "This #{t('investigation')} does not match the identifier provided in the FAIR Data Station metadata" + error = true + else + begin + Investigation.transaction do + @investigation = Seek::FairDataStation::Writer.new.update_isa(@investigation, datastation_inv, current_person, @investigation.projects, @investigation.policy) + @investigation.save! + end + rescue ActiveRecord::RecordInvalid => e + flash[:error] = e.message + error = true + end + end + if error respond_to do |format| format.html { render action: :update_from_fairdata_station, status: :unprocessable_entity } end else - @investigation = Seek::FairDataStation::Writer.new.update_isa(@investigation, datastation_inv, current_person, @investigation.projects, @investigation.policy) - @investigation.save! respond_to do |format| format.html { redirect_to(@investigation) } end end - - end def export_isatab_json diff --git a/test/fixtures/files/fairdatastation/seek-fair-data-station-invalid-test-case.ttl b/test/fixtures/files/fairdatastation/seek-fair-data-station-invalid-test-case.ttl new file mode 100755 index 0000000000..4bb491c95c --- /dev/null +++ b/test/fixtures/files/fairdatastation/seek-fair-data-station-invalid-test-case.ttl @@ -0,0 +1,353 @@ +@prefix base: . +@prefix bibo: . +@prefix dc: . +@prefix dcmitype: . +@prefix empusa: . +@prefix fair: . +@prefix foaf: . +@prefix gbol: . +@prefix jerm: . +@prefix mixs: . +@prefix owl: . +@prefix ppeo: . +@prefix prov: . +@prefix rdf: . +@prefix rdfs: . +@prefix sample: . +@prefix schema: . +@prefix sschema: . +@prefix uniprot: . +@prefix unlock: . +@prefix void: . +@prefix wd: . +@prefix wdt: . +@prefix wv: . +@prefix xml: . +@prefix xsd: . + +fair:inv_seek-test-investigation + rdf:type jerm:Investigation ; + fair:associated_publication "10.1371/journal.pone.0071377" ; + jerm:hasPart , ; + schema:contributor ; + schema:description "testing testing testing testing testing testing testing testing testing testing inv" ; + schema:identifier "seek-test-investigation" ; + schema:title "An Investigation for a SEEK test case" . + + + rdf:type schema:Person ; + schema:department "Computer Science" ; + schema:email ; + schema:familyName "Jones" ; + schema:givenName "Tom Jones" ; + schema:memberOf . + + + rdf:type schema:Organization ; + schema:legalName "University of Manchester" . + +schema:identifier rdf:type rdf:Property ; + rdfs:label "investigation identifier" ; + schema:description "Identifier corresponding to the investigation" ; + schema:valuePattern "^[a-zA-Z0-9-_]*${5,25}" ; + schema:valueRequired true . + +schema:description rdf:type rdf:Property ; + rdfs:label "investigation description" ; + schema:description "Description of the investigation" ; + schema:valuePattern ".*{50,}" ; + schema:valueRequired true . + +schema:title rdf:type rdf:Property ; + rdfs:label "investigation title" ; + schema:description "Title describing the investigation" ; + schema:valuePattern ".*{10,}" ; + schema:valueRequired true . + +fair:associated_publication + rdf:type rdf:Property ; + rdfs:label "associated publication" ; + schema:description "An identifier for a literature publication where the investigation is described. Use of DOIs is recommended." ; + schema:valuePattern "^(10\\.\\d{4,5}\\/[\\S]+[^;,.\\s])$" ; + schema:valueRequired false . + + + rdf:type jerm:Study ; + fair:end_date_of_study "2024-08-08"^^xsd:date ; + fair:experimental_site_name "manchester test site" ; + fair:start_date_of_study "2024-08-01"^^xsd:date ; + jerm:hasPart ; + schema:description "testing testing testing testing testing testing testing testing testing testing study 1" ; + schema:identifier "seek-test-study-1" ; + schema:title "test study 1" . + +fair:start_date_of_study + rdf:type rdf:Property ; + rdfs:label "start date of study" ; + schema:description "Date and, if relevant, time when the experiment started" ; + schema:valuePattern ".+" ; + schema:valueRequired false . + +fair:end_date_of_study + rdf:type rdf:Property ; + rdfs:label "end date of study" ; + schema:description "Date and, if relevant, time when the experiment ended" ; + schema:valuePattern ".+" ; + schema:valueRequired false . + +fair:experimental_site_name + rdf:type rdf:Property ; + rdfs:label "experimental site name" ; + schema:description "The name of the natural site, experimental field, greenhouse, phenotyping facility, etc. where the experiment took place." ; + schema:valuePattern ".*" ; + schema:valueRequired false . + + + rdf:type jerm:Study ; + fair:end_date_of_study "2024-08-18"^^xsd:date ; + fair:experimental_site_name "manchester test site" ; + fair:start_date_of_study "2024-08-10"^^xsd:date ; + jerm:hasPart , ; + schema:description "testing testing testing testing testing testing testing testing testing testing study 2" ; + schema:identifier "seek-test-study-2" ; + schema:title "" . + + + rdf:type ppeo:observation_unit ; + fair:birth_weight "1234g" ; + fair:date_of_birth "2020-01-10"^^xsd:date ; + jerm:hasPart ; + schema:dataset ; + schema:description "testing testing testing testing testing testing testing testing testing testing obs unit 1" ; + schema:identifier "seek-test-obs-unit-1" ; + schema:name "test obs unit 1 - changed" ; + mixs:0000811 "male" . + +schema:name rdf:type rdf:Property ; + rdfs:label "observation unit name" ; + schema:description "Name of the entity being observed" ; + schema:valuePattern ".*{10,}" ; + schema:valueRequired true . + +fair:date_of_birth rdf:type rdf:Property ; + rdfs:label "date of birth" ; + schema:description "Date of birth of subject the sample was derived from." ; + schema:valuePattern ".+" ; + schema:valueRequired false . + +mixs:0000811 rdf:type rdf:Property ; + rdfs:label "host sex" ; + schema:description "Gender or sex of the host." ; + schema:valuePattern "(female|hermaphrodite|male|neuter|not applicable|not collected|not provided|other|restricted access)" ; + schema:valueRequired false . + +fair:birth_weight rdf:type rdf:Property ; + rdfs:label "birth weight" ; + schema:description "Individual birth weight of piglets" ; + schema:unitCode "g" ; + schema:valuePattern "^(\\-|\\+)?(\\d+)(\\.\\d+)? ?(g)" ; + schema:valueRequired false . + + + rdf:type jerm:Data_sample ; + schema:description "file" ; + schema:identifier "test-file-1.csv" . + +sschema:dataset rdf:type rdf:Property ; + rdfs:label "file" ; + schema:description "Filename or the path of a file" ; + schema:valuePattern ".*" ; + schema:valueRequired false . + + + rdf:type ppeo:observation_unit ; + fair:birth_weight "1235g" ; + fair:date_of_birth "2020-01-11"^^xsd:date ; + jerm:hasPart , ; + schema:dataset ; + schema:description "testing testing testing testing testing testing testing testing testing testing obs unit 2" ; + schema:identifier "seek-test-obs-unit-2" ; + schema:name "test obs unit 2" ; + mixs:0000811 "female" . + + + rdf:type ppeo:observation_unit ; + fair:birth_weight "1236g" ; + fair:date_of_birth "2020-01-12"^^xsd:date ; + jerm:hasPart , ; + schema:dataset ; + schema:description "testing testing testing testing testing testing testing testing testing testing obs unit 3" ; + schema:identifier "seek-test-obs-unit-3" ; + schema:name "test obs unit 3" ; + mixs:0000811 "male" . + + + rdf:type jerm:Data_sample ; + schema:description "file" ; + schema:identifier "test-file-2.csv" . + + + rdf:type jerm:Sample ; + fair:biosafety_level 1 ; + gbol:scientificName "pig" ; + jerm:hasPart ; + uniprot:organism 123456 ; + schema:description "testing testing testing testing testing testing testing testing testing testing sample 1" ; + schema:identifier "seek-test-sample-1" ; + schema:name "" ; + mixs:0000011 "2024-08-20"^^xsd:date . + +uniprot:organism rdf:type rdf:Property ; + rdfs:label "ncbi taxonomy id" ; + schema:description "Taxonomic identifier of the sample according to https://www.ncbi.nlm.nih.gov/Taxonomy/Browser/wwwtax.cgi for example use 2582415 for a blank sample or 1510822 for pig metagenome" ; + schema:valuePattern "\\d+" ; + schema:valueRequired true . + +gbol:scientificName rdf:type rdf:Property ; + rdfs:label "scientific name" ; + schema:description "Name of the organism" ; + schema:valuePattern ".*" ; + schema:valueRequired true . + +fair:biosafety_level rdf:type rdf:Property ; + rdfs:label "biosafety level" ; + schema:description "Biosafety level of the corresponding sample" ; + schema:valuePattern "(1|2|3|4|unknown)" ; + schema:valueRequired true . + +mixs:0000011 rdf:type rdf:Property ; + rdfs:label "collection date" ; + schema:description "The date of sampling, either as an instance (single point in time) or interval. In case no exact time is available, the date/time can be right truncated i.e. all of these are valid ISO8601 compliant times: 2008-01-23T19:23:10+00:00; 2008-01-23T19:23:10; 2008-01-23; 2008-01; 2008." ; + schema:valuePattern ".+" ; + schema:valueRequired true . + + + rdf:type jerm:Sample ; + fair:biosafety_level 1 ; + gbol:scientificName "camel" ; + jerm:hasPart ; + uniprot:organism 123457 ; + schema:description "testing testing testing testing testing testing testing testing testing testing sample 2" ; + schema:identifier "seek-test-sample-2" ; + schema:name "test seek sample 2" ; + mixs:0000011 "2024-08-21"^^xsd:date . + + + rdf:type jerm:Sample ; + fair:biosafety_level 2 ; + gbol:scientificName "cat" ; + jerm:hasPart ; + uniprot:organism 123458 ; + schema:description "testing testing testing testing testing testing testing testing testing testing sample 3" ; + schema:identifier "seek-test-sample-3" ; + schema:name "test seek sample 3" ; + mixs:0000011 "2024-08-22"^^xsd:date . + + + rdf:type jerm:Sample ; + fair:biosafety_level 1 ; + gbol:scientificName "dog" ; + jerm:hasPart ; + uniprot:organism 123459 ; + schema:description "testing testing testing testing testing testing testing testing testing testing sample 4" ; + schema:identifier "seek-test-sample-4" ; + schema:name "test seek sample 4" ; + mixs:0000011 "2024-08-23"^^xsd:date . + + + rdf:type jerm:Sample ; + fair:biosafety_level "unknown" ; + gbol:scientificName "pig" ; + jerm:hasPart , ; + uniprot:organism 123456 ; + schema:description "testing testing testing testing testing testing testing testing testing testing sample 5" ; + schema:identifier "seek-test-sample-5" ; + schema:name "test seek sample 5" ; + mixs:0000011 "2024-08-24"^^xsd:date . + + + rdf:type jerm:Assay ; + fair:facility "test facility" ; + fair:protocol "sop 1" ; + schema:dataset ; + schema:dateCreated "2024-09-10"^^xsd:date ; + schema:description "testing testing testing testing testing testing testing testing testing testing assay 1" ; + schema:identifier "seek-test-assay-1" . + +fair:facility rdf:type rdf:Property ; + rdfs:label "facility" ; + schema:description "The facility that was used for generating the data" ; + schema:valuePattern ".*" ; + schema:valueRequired true . + +schema:dateCreated rdf:type rdf:Property ; + rdfs:label "assay date" ; + schema:description "The date when the data generation took place" ; + schema:valuePattern ".+" ; + schema:valueRequired true . + +fair:protocol rdf:type rdf:Property ; + rdfs:label "protocol" ; + schema:description "The protocol used for preparation or isolation (name or url) used to create the assay" ; + schema:valuePattern ".*" ; + schema:valueRequired true . + + + rdf:type jerm:Assay ; + fair:facility "test facility" ; + fair:protocol "protocol 2" ; + schema:dataset ; + schema:dateCreated "2024-09-11"^^xsd:date ; + schema:description "testing testing testing testing testing testing testing testing testing testing assay 2" ; + schema:identifier "seek-test-assay-2" . + + + rdf:type jerm:Assay ; + fair:facility "test facility" ; + fair:protocol "sop 3" ; + schema:dataset ; + schema:dateCreated "2024-09-12"^^xsd:date ; + schema:description "testing testing testing testing testing testing testing testing testing testing assay 3" ; + schema:identifier "seek-test-assay-3" . + + + rdf:type jerm:Data_sample ; + schema:description "file" ; + schema:identifier "test-file-3.csv" . + + + rdf:type jerm:Assay ; + fair:facility "test facility" ; + fair:protocol "sop 4" ; + schema:dataset ; + schema:dateCreated "2024-09-13"^^xsd:date ; + schema:description "testing testing testing testing testing testing testing testing testing testing assay 4" ; + schema:identifier "seek-test-assay-4" . + + + rdf:type jerm:Data_sample ; + schema:description "file" ; + schema:identifier "test-file-4.csv" . + + + rdf:type jerm:Assay ; + fair:facility "test facility" ; + fair:protocol "sop 5" ; + schema:dataset ; + schema:dateCreated "2024-09-14"^^xsd:date ; + schema:description "testing testing testing testing testing testing testing testing testing testing assay 5" ; + schema:identifier "seek-test-assay-5" . + + + rdf:type jerm:Data_sample ; + schema:description "file" ; + schema:identifier "test-file-5.csv" . + + + rdf:type jerm:Assay ; + fair:facility "test facility" ; + fair:protocol "sop 6" ; + schema:dataset ; + schema:dateCreated "2024-09-15"^^xsd:date ; + schema:description "testing testing testing testing testing testing testing testing testing testing assay 6" ; + schema:identifier "seek-test-assay-6" . diff --git a/test/functional/investigations_controller_test.rb b/test/functional/investigations_controller_test.rb index 63ddc6c9f5..57ee30a3dd 100644 --- a/test/functional/investigations_controller_test.rb +++ b/test/functional/investigations_controller_test.rb @@ -1387,6 +1387,33 @@ def test_title end end + test 'submit from fair data station invalid metadata' do + investigation = setup_test_case_investigation + login_as(investigation.contributor) + ttl_file = fixture_file_upload('fairdatastation/seek-fair-data-station-invalid-test-case.ttl') + + assert_no_difference('Investigation.count') do + assert_no_difference('Study.count') do + assert_no_difference('ObservationUnit.count') do + assert_no_difference('Sample.count') do + assert_no_difference('Assay.count') do + post :submit_fairdata_station, params: {id: investigation, datastation_data: ttl_file } + assert_response :unprocessable_entity + assert_match /Validation failed: Title can't be blank, Title is required/, flash[:error] + assert_select 'div#error_flash', text: /Validation failed: Title can't be blank, Title is required/ + end + end + end + end + end + + assert_equal 'test study 2', Study.by_external_identifier('seek-test-study-2', investigation.projects).title + assert_equal 'test seek sample 1', Sample.by_external_identifier('seek-test-sample-1', investigation.projects).title + + # this may have changed in an update before the error, so this checks the transaction is behaving correctly and rolling back + assert_equal 'test obs unit 1', ObservationUnit.by_external_identifier('seek-test-obs-unit-1', investigation.projects).title + end + private def setup_test_case_investigation